進(jìn)程
1.運(yùn)行時(shí)(runtime)應(yīng)用程序
2.進(jìn)程之間的內(nèi)存不是共享(獨(dú)占)
3.進(jìn)程間通信使用socket(套接字)
多線(xiàn)程
1.進(jìn)程內(nèi)并發(fā)執(zhí)行的代碼段
2.線(xiàn)程之間共享內(nèi)存
3.每個(gè)運(yùn)行著的線(xiàn)程對(duì)應(yīng)一個(gè)stack
4.應(yīng)用線(xiàn)程至少有一個(gè)線(xiàn)程(主線(xiàn)程)
1.Thread.yield()方法
讓當(dāng)前線(xiàn)程讓出CPU的搶占權(quán)逗宜,瞬時(shí)的動(dòng)作。
2.Thread.sleep()
讓當(dāng)前線(xiàn)程休眠指定毫秒數(shù)
釋放CPU搶占權(quán)纺讲,和鎖旗標(biāo)沒(méi)有關(guān)系。
3.Object: wait
讓當(dāng)前線(xiàn)程進(jìn)入鎖旗標(biāo)的等待隊(duì)列逢渔。釋放CPU搶占權(quán)乡括,還釋放鎖旗標(biāo)的監(jiān)控權(quán)冲簿。
字符在內(nèi)存中存儲(chǔ)都是unicode編碼亿昏。
要注意:將對(duì)象傳遞給線(xiàn)程時(shí),傳遞的只是對(duì)象的引用吝沫,而不是對(duì)象的拷貝
public class TestCase1 {
@Test
public void test4() throws InterruptedException {
Zhong zhong = new Zhong();
Thread t1 = new MyThread2(zhong, "中秋快樂(lè)");
Thread t2 = new MyThread2(zhong, "你就是我最美的期待");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("所有線(xiàn)程結(jié)束");
System.out.println(Thread.currentThread().getName() + ", zhong = " + zhong + ", desc = " + zhong.getDesc());
}
}
class MyThread2 extends Thread{
private Zhong zhong;
public MyThread2(Zhong zhong, String desc) {
this.zhong = zhong;
this.zhong.setDesc(desc);
}
public void run() {
System.out.println(Thread.currentThread().getName() + ", zhong = " + zhong + ", desc = " + zhong.getDesc());
}
}
class Zhong{
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
打印結(jié)果:
Thread-0, zhong = day16.Zhong@70212102, desc = 你就是我最美的期待
Thread-1, zhong = day16.Zhong@70212102, desc = 你就是我最美的期待
所有線(xiàn)程結(jié)束
main, zhong = day16.Zhong@70212102, desc = 你就是我最美的期待
繼承Thread并重寫(xiě)run方法來(lái)定義線(xiàn)程
* 第一種創(chuàng)建線(xiàn)程的方式
* 繼承Thread并重寫(xiě)run方法來(lái)定義線(xiàn)程要執(zhí)行的任務(wù)
public class Demo1 {
public static void main(String[] args) {
myThread1 t1 = new myThread1();
myThread2 t2 = new myThread2();
* 啟動(dòng)線(xiàn)程要指定start方法惨险,而不是直接調(diào)用run方法脊髓,
* run方法時(shí)線(xiàn)程要執(zhí)行的任務(wù)。
* 當(dāng)線(xiàn)程的start方法被調(diào)用后将硝, 線(xiàn)程進(jìn)入runnable狀態(tài)依疼,
* 一旦獲取cpu時(shí)間,run方法會(huì)自動(dòng)調(diào)用律罢。
t1.start();
t2.start();
}
}
* 這種創(chuàng)建線(xiàn)程的方式有兩個(gè)不足:
* 1. 由于java是單繼承,那么當(dāng)繼承了Thread后沧踏,就無(wú)法再繼承其他類(lèi)巾钉。
*
* 2.由于繼承Thread后重寫(xiě)run方法規(guī)定了線(xiàn)程執(zhí)行的任務(wù),
* 這就導(dǎo)致線(xiàn)程與任務(wù)有一個(gè)必然的耦合關(guān)系盒蟆,不利于線(xiàn)程的重用师骗。
class myThread1 extends Thread{
public void run() {
for(int i=0; i<250; i++) {
System.out.print("*");
if(i>0 && i%50==0) {
System.out.println();
}
}
}
}
class myThread2 extends Thread{
public void run(){
for(int i=0; i<250; i++) {
System.out.print("-");
if(i%50==0) {
System.out.println();
}
}
}
}
實(shí)現(xiàn)Runnable接口并重寫(xiě)run方法,實(shí)例傳入Thread中
* 第二種創(chuàng)建線(xiàn)程的方式
* 實(shí)現(xiàn)Runnable接口并重寫(xiě)run方法
public class Demo2 {
public static void main(String[] args) {
MyRunnable1 r1 = new MyRunnable1();
MyRunnable2 r2 = new MyRunnable2();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
class MyRunnable1 implements Runnable{
public void run() {
for(int i=0; i<250; i++) {
System.out.print("*");
if(i%50==0) {
System.out.println();
}
}
}
}
class MyRunnable2 implements Runnable{
public void run() {
for(int i=0; i<250; i++) {
System.out.print("-");
if(i%50==0) {
System.out.println();
}
}
}
}
匿名內(nèi)部類(lèi)創(chuàng)建上面兩種線(xiàn)程
* 使用匿名內(nèi)部類(lèi)來(lái)完成方式一與方式二的線(xiàn)程創(chuàng)建
public class Demo3 {
public static void main(String[] args) {
Thread t1 = new Thread(){
public void run() {
for(int i=1; i<251; i++) {
System.out.print("*");
if(i%50 == 0) {
System.out.println();
}
}
}
};
t1.start();
-------------方式二
new Thread(new Runnable() {
public void run() {
for(int i=1; i<250; i++) {
System.out.print("-");
if(i%50 == 0) {
System.out.println();
}
}
}
}).start();
}
}
獲取運(yùn)行當(dāng)前方法的線(xiàn)程寒屯,Thread.currentThread()
* static Thread currentThread()
* 獲取運(yùn)行當(dāng)前方法的線(xiàn)程
public class Demo4 {
public static void main(String[] args) {
Thread main = Thread.currentThread();
System.out.println("運(yùn)行main線(xiàn)程:" + main);
dosome();
}
public static void dosome() {
Thread t = Thread.currentThread();
System.out.println("運(yùn)行dosome線(xiàn)程:"+t);
Thread t2 = new Thread() {
public void run() {
System.out.println("運(yùn)行自建線(xiàn)程:"+Thread.currentThread());
}
};
t2.start();
}
}
打庸鸭小:
運(yùn)行main線(xiàn)程:Thread[main,5,main]
運(yùn)行dosome線(xiàn)程:Thread[main,5,main]
運(yùn)行自建線(xiàn)程:Thread[Thread-0,5,main]
獲取線(xiàn)程相關(guān)信息的方法
* 獲取線(xiàn)程相關(guān)信息的方法
public class Demo5 {
public static void main(String[] args) {
Thread main = Thread.currentThread();
String mainName = main.getName();
long mainId = main.getId();
int priority = main.getPriority();
System.out.println("name:"+mainName);
System.out.println("id:"+mainId);
System.out.println("優(yōu)先級(jí):"+priority);
boolean isAlive = main.isAlive();
System.out.println("是否存活"+isAlive);
boolean isDaemon = main.isDaemon();
System.out.println("是否是守護(hù)線(xiàn)程:"+isDaemon);
boolean isInterrupted = main.isInterrupted();
System.out.println("是否中斷:"+isInterrupted);
}
}
打印:
name:main
id:1
優(yōu)先級(jí):5
是否存活true
是否是守護(hù)線(xiàn)程:false
是否中斷:false
* 線(xiàn)程優(yōu)先級(jí)
* 線(xiàn)程的時(shí)間片分配完全聽(tīng)線(xiàn)程調(diào)度的魂角,線(xiàn)程只能被動(dòng)的被分配時(shí)間智绸,對(duì)于線(xiàn)程調(diào)度的工作不能干預(yù)。
*
* 但是可以通過(guò)提高線(xiàn)程的優(yōu)先級(jí)來(lái)達(dá)到盡可能干預(yù)的目的斯稳。
* 理論上迹恐,優(yōu)先級(jí)越高的線(xiàn)程,獲取CPU的時(shí)間片的次數(shù)就越多殴边。
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
sleep,線(xiàn)程堵塞
import java.text.SimpleDateFormat;
import java.util.Date;
* static void sleep(long ms)
* 線(xiàn)程提供的靜態(tài)方法sleep可以使運(yùn)行該方法的線(xiàn)程進(jìn)入堵塞
* 狀態(tài)指定毫秒唇辨,超時(shí)后線(xiàn)程會(huì)自動(dòng)回到RUNNABLE狀態(tài)能耻。
public class Demo7 {
public static void main(String[] args) {
while(true) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String time = sdf.format(new Date());
System.out.println(time);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打油龀邸: 一秒鐘打印一次當(dāng)前時(shí)間
08:25:16
08:25:17
08:25:18
yield方法讓出CPU時(shí)間
* yield方法
* Thread的靜態(tài)方法yield:static void yield()
* 該方法用于使當(dāng)前線(xiàn)程主動(dòng)讓出當(dāng)次CPU時(shí)間片段回到RUNNABLE狀態(tài),等待分配時(shí)間片戒职。
package archive;
public class cc {
public static void main(String[] args) {
Thread t1 = new MyThread("Thread-1");
Thread t2 = new MyThread("Thread-2");
t1.start();
t2.start();
}
}
class MyThread extends Thread{
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() {
for(;;) {
System.out.println(name);
Thread.yield();
}
}
}
守護(hù)線(xiàn)程透乾,所有前臺(tái)線(xiàn)程結(jié)束,守護(hù)線(xiàn)程就會(huì)被結(jié)束
* 守護(hù)線(xiàn)程捧韵,又稱(chēng)為后臺(tái)線(xiàn)程
* 當(dāng)一個(gè)進(jìn)程中的所有前臺(tái)線(xiàn)程都結(jié)束時(shí)汉操,進(jìn)程就要結(jié)束,
* 若還有后臺(tái)線(xiàn)程運(yùn)行芒篷,那么后臺(tái)線(xiàn)程會(huì)被強(qiáng)制結(jié)束。
public class Demo8 {
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
for(int i=0; i<10; i++) {
System.out.println("hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread() {
public void run() {
while(true) {
System.out.println("hi");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
-------- 設(shè)置為后臺(tái)線(xiàn)程挠他,并且要在start前調(diào)用
t2.setDaemon(true);
t1.start();
t2.start();
}
}
運(yùn)行結(jié)果:
t2 跟隨 t1 結(jié)束而結(jié)束
* main方法是一個(gè)前臺(tái)線(xiàn)程篡帕,GC是一個(gè)后臺(tái)線(xiàn)程
join 堵塞線(xiàn)程,等待某個(gè)線(xiàn)程執(zhí)行完畢愉耙,再繼續(xù)執(zhí)行
* void join()
* join方法可以使調(diào)用該方法的線(xiàn)程進(jìn)入堵塞狀態(tài)拌滋,直到該方法所屬
* 線(xiàn)程完成工作才會(huì)解除調(diào)用該方法線(xiàn)程的堵塞狀態(tài)朴沿。
* join方法一般用來(lái)完成多個(gè)線(xiàn)程之間的同步工作問(wèn)題赌渣。
public class Demo9 {
static boolean isFinish = false;
public static void main(String[] args) {
Thread download = new Thread() {
public void run() {
for(int i=1; i<=6; i++) {
System.out.println("download:"+i+"%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("download is successful");
isFinish = true;
}
};
Thread show = new Thread() {
public void run() {
System.out.println("showing");
-- 要先等待圖片下載完畢
try {
download.join(); ---- 等待download線(xiàn)程執(zhí)行完畢
} catch (InterruptedException e) {
e.printStackTrace();
}
if(!isFinish) {
throw new RuntimeException("show:圖片顯示異常");
}
System.out.println("show end");
}
};
download.start();
show.start();
}
}
打硬獭:
showing
download:1%
download:2%
download:3%
download:4%
download:5%
download:6%
download is successful
show end
一個(gè)很明顯join堵塞的例子
package archive;
public class cc {
public static void main(String[] args) {
Thread t1 = new MyThread("Thread-4", 4000);
Thread t2 = new MyThread("Thread-3", 3000);
Thread t3 = new MyThread("Thread-2", 2000);
Thread t4 = new MyThread("Thread-1", 1000);
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
System.out.println("-----------");
t2.join();
System.out.println("-----------");
t3.join();
System.out.println("-----------");
t4.join();
}catch(Exception e) {
e.printStackTrace();
}
}
}
class MyThread extends Thread{
private String name;
private int time;
public MyThread(String name, int time) {
this.name = name;
this.time = time;
}
public void run() {
System.out.println(name + "等待");
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "到了");
}
}
在t1.join()堵塞直到t1線(xiàn)程結(jié)束后才走下一句
執(zhí)行結(jié)果:
Thread-3等待
Thread-1等待
Thread-2等待
Thread-4等待
Thread-1到了
Thread-2到了
Thread-3到了
Thread-4到了
-----------
-----------
-----------
synchronized斜姥,同步鎖,線(xiàn)程排隊(duì)執(zhí)行
在方法上添加铸敏,是給對(duì)象加鎖杈笔,如果是靜態(tài)方法,靜態(tài)方法所屬類(lèi)蒙具,就是給類(lèi)加鎖
* 多線(xiàn)程并發(fā)訪(fǎng)問(wèn)同一資源時(shí),就會(huì)形成“搶”的現(xiàn)象持钉,
* 由于線(xiàn)程切換時(shí)機(jī)不確定融师,可能導(dǎo)致執(zhí)行代碼順序的混亂右钾,嚴(yán)重時(shí)會(huì)導(dǎo)致系統(tǒng)癱瘓。
*
* 當(dāng)一個(gè)方法被synchronized修飾后,該方法為同步方法舀射,
* 即:多個(gè)線(xiàn)程不能同時(shí)進(jìn)入方法內(nèi)部執(zhí)行窘茁。
* 對(duì)于成員方法而言,synchronized會(huì)在一個(gè)線(xiàn)程調(diào)用該方法將該方法所屬對(duì)象加鎖脆烟,
* 其他線(xiàn)程在執(zhí)行該方法時(shí)由于執(zhí)行方法的線(xiàn)程沒(méi)有釋放鎖山林,所以只能在方法外堵塞,
* 直到持有方法鎖的線(xiàn)程將方法執(zhí)行完畢邢羔。
* 所以驼抹,解決多線(xiàn)程并發(fā)執(zhí)行安全問(wèn)題的辦法就是將"搶"變?yōu)?排隊(duì)"
public class Demo1 {
public static void main(String[] args) {
Bean bean = new Bean();
Thread t1 = new Thread() {
public void run() {
while(true) {
bean.OperateB();
}
}
};
Thread t2 = new Thread() {
public void run() {
while(true) {
bean.OperateB();
}
}
};
t1.start();
t2.start();
}
}
class Bean{
static int b = 20;
public synchronized void OperateB() {
b--;
if(b<=0) {
throw new RuntimeException("b is end!");
}else {
System.out.println(Thread.currentThread()+" b="+b);
}
}
}
同步塊,塊中的代碼同一時(shí)間只能被一個(gè)線(xiàn)程執(zhí)行
* 同步塊
* 有效的縮小同步范圍可以在保證并發(fā)安全的同時(shí)盡可能提高并發(fā)效率拜鹤。
*
* 同步塊可以要求多個(gè)線(xiàn)程對(duì)該塊內(nèi)的代碼排隊(duì)執(zhí)行框冀,但是前提條件是
* 同步監(jiān)視器對(duì)象即(上鎖的對(duì)象)要求多個(gè)線(xiàn)程看到的必須是同一個(gè)敏簿。
*
* synchronized(同步監(jiān)視器對(duì)象){
* 需要同步的代碼
* }
*
* 所謂同步執(zhí)行即:多個(gè)線(xiàn)程必須排隊(duì)執(zhí)行
* 所謂異步執(zhí)行即:多個(gè)線(xiàn)程可以同時(shí)執(zhí)行
public class Demo2 {
public static void main(String[] args) {
Shop shop = new Shop();
Thread t1 = new Thread() {
public void run() {
shop.buy();
}
};
Thread t2 = new Thread() {
public void run() {
shop.buy();
}
};
t1.start();
t2.start();
}
}
class Shop{
public void buy() {
System.out.println("shop is begin");
try {
Thread.sleep(2000);
synchronized (this) {
System.out.println(Thread.currentThread() + "--hello");
Thread.sleep(2000);
}
}catch(Exception e) {
}
System.out.println("shop is end");
}
}
注意:
synchronized(this)
當(dāng)中 this 指代的是 synchronized 所在的【對(duì)象】明也,
為 this 時(shí)本程序的執(zhí)行的結(jié)果是:
shop is begin
shop is begin
Thread[Thread-1,5,main]--hello --- 鎖住了
shop is end
Thread[Thread-0,5,main]--hello
shop is end
當(dāng) this 改為 new Object 時(shí),
shop is begin
shop is begin
Thread[Thread-0,5,main]--hello --- 鎖無(wú)效了
Thread[Thread-1,5,main]--hello
shop is end
shop is end
同步監(jiān)視器對(duì)象即(上鎖的對(duì)象)要求多個(gè)線(xiàn)程看到的必須是同一個(gè)惯裕。
類(lèi)的靜態(tài)方法加上 sysnchronized温数,那么類(lèi)實(shí)例出來(lái)的對(duì)象執(zhí)行該方法時(shí)也是具有同步鎖的效果,因?yàn)樵摲椒ㄈ志鸵环蒡呤疲c對(duì)象無(wú)關(guān)
* 靜態(tài)方法的同步鎖
* 當(dāng)一個(gè)靜態(tài)方法被synchronized修飾后撑刺,那么該方法即為同步方法,
* 由于靜態(tài)方法從屬類(lèi)握玛,全局就一份够傍,所以同步的靜態(tài)方法一定具有同步鎖效果,與對(duì)象無(wú)關(guān)挠铲。
public class Demo3 {
public static void main(String[] args) {
Foo f1 = new Foo();
Foo f2 = new Foo();
Thread t1 = new Thread() {
public void run() {
f1.dosome();
}
};
Thread t2 = new Thread() {
public void run() {
f2.dosome();
}
};
t1.start();
t2.start();
}
}
class Foo{
public synchronized static void dosome() {
try {
System.out.println("dosome");
Thread t = Thread.currentThread();
System.out.println(t.getName()+": dosome is running");
Thread.sleep(3000);
System.out.println(t.getName()+": dosome is end");
}catch(Exception e) {
e.printStackTrace();
}
}
}
打油醮:
dosome
Thread-0: dosome is running
Thread-0: dosome is end
dosome
Thread-1: dosome is running
Thread-1: dosome is end
互斥鎖,市殷,要十分注意鎖的對(duì)象在多線(xiàn)程中看到的是否是同一個(gè)
* 互斥鎖
* synchronized也叫互斥鎖,即:
* 使用synchronized修飾多段代碼刹衫,只要他們的同步監(jiān)視器對(duì)象相同醋寝,
* 那么這幾段代碼間就是互斥關(guān)系,即:多個(gè)線(xiàn)程不能同時(shí)執(zhí)行這些代碼
public class Demo4 {
public static void main(String[] args) {
Foo1 foo = new Foo1();
Thread t1 = new Thread() {
public void run() {
foo.methA();
}
};
Thread t2 = new Thread() {
public void run() {
foo.methB();
}
};
t1.start();
t2.start();
}
}
class Foo1{
public synchronized void methA() {
try {
System.out.println("methA is begin");
Thread.sleep(4000);
System.out.println("methA is end");
}catch(Exception e) {
}
}
public synchronized void methB() {
try {
System.out.println("methB is begin");
Thread.sleep(4000);
System.out.println("methB is end");
}catch(Exception e) {
}
}
}
打哟佟:
methA is begin ----- 盡管運(yùn)行的不是同一個(gè)方法音羞,但是鎖的是同一個(gè)對(duì)象
methA is end
methB is begin
methB is end
** 注意:互斥鎖修飾多段代碼,同步鎖修飾一段代碼
ArrayList仓犬,HashSet 嗅绰,HashMap 都不支持線(xiàn)程安全,要使用Collections內(nèi)置的靜態(tài)方法轉(zhuǎn)換為線(xiàn)程安全的數(shù)據(jù)模型。
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Demo5 {
public static void main(String[] args) {
* ArrayList 不是線(xiàn)程安全的
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
System.out.println(list);
* 將給定集合轉(zhuǎn)換為線(xiàn)程安全的集合
list = Collections.synchronizedList(list);
System.out.println(list);
* HashSet 不是線(xiàn)程安全的
Set<String> set = new HashSet<String>(list);
set.add("a");
set.add("b");
System.out.println(set);
* 將給定的 Set 集合轉(zhuǎn)換為線(xiàn)程安全的
set = Collections.synchronizedSet(set);
System.out.println(set);
* HashMap 也不是線(xiàn)程安全的
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("Language",98);
map.put("Math",90);
map.put("Englist",80);
System.out.println(map);
* 將 Map 轉(zhuǎn)換為線(xiàn)程安全的
map = Collections.synchronizedMap(map);
System.out.println(map);
}
}
* API手冊(cè)上有說(shuō)明
* 就算是線(xiàn)程安全的集合那么其中對(duì)于元素的操作窘面,如:add翠语,remove等方法
* 都不予迭代器遍歷做互斥,需要自行維護(hù)互斥關(guān)系财边。
線(xiàn)程池肌括,重用線(xiàn)程,控制線(xiàn)程數(shù)量
* 線(xiàn)程池
* 線(xiàn)程池主要有兩個(gè)作用:
* 1. 重用線(xiàn)程 ----- 而不是銷(xiāo)毀后重建線(xiàn)程
* 2. 控制線(xiàn)程數(shù)量
* 當(dāng)我們的應(yīng)用需要?jiǎng)?chuàng)建大量線(xiàn)程或者發(fā)現(xiàn)線(xiàn)程會(huì)頻繁的創(chuàng)建和銷(xiāo)毀時(shí)
* 就應(yīng)當(dāng)考慮使用線(xiàn)程池來(lái)維護(hù)線(xiàn)程酣难。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo6 {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(2);
for(int i=0; i<3; i++) {
Runnable runn = new Runnable() {
public void run() {
Thread t = Thread.currentThread();
try {
System.out.println(t.getName()+"線(xiàn)程開(kāi)始");
Thread.sleep(3000);
System.out.println(t.getName()+"線(xiàn)程結(jié)束");
}catch(Exception e) {
e.printStackTrace();
}
}
};
threadPool.execute(runn);
System.out.println("指派了一個(gè)任務(wù)");
}
System.out.println("設(shè)置結(jié)束");
* 停止線(xiàn)程池有兩種方式:
* 1. threadPool.shutdown(); ---- 分配的任務(wù)執(zhí)行完畢就銷(xiāo)毀所有線(xiàn)程
* 2. threadPool.shutdownNow(); ---- 立即結(jié)束所有線(xiàn)程
threadPool.shutdown();
}
}