1.什么是線程
在并發(fā)編程中蓝丙,有兩個基本的執(zhí)行單元:進(jìn)程和線程。在Java編程語言中望拖,并發(fā)編程主要關(guān)注線程渺尘。
線程有時稱為輕量級進(jìn)程。進(jìn)程和線程都提供了一個執(zhí)行環(huán)境靠娱,但創(chuàng)建一個新線程所需的資源要少于創(chuàng)建新進(jìn)程的資源沧烈。
線程存在于一個進(jìn)程中, 每個進(jìn)程至少有一個線程像云。線程共享進(jìn)程的資源锌雀,包括內(nèi)存和打開的文件。這使得溝通有效但可能有問題迅诬。
2.線程生命周期
- 新建狀態(tài)(New):新創(chuàng)建了一個線程對象腋逆。
- 就緒狀態(tài)(Runnable):線程對象創(chuàng)建后,其他線程調(diào)用了該對象的start()方法侈贷。該狀態(tài)的線程位于可運行線程池中惩歉,變得可運行,等待獲取CPU的使用權(quán)俏蛮。
- 運行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU撑蚌,執(zhí)行程序代碼。
-
阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因為某種原因放棄CPU使用權(quán)搏屑,暫時停止運行争涌。直到線程進(jìn)入就緒狀態(tài),才有機(jī)會轉(zhuǎn)到運行狀態(tài)辣恋。阻塞的情況分三種:
(一). 等待阻塞:運行的線程執(zhí)行wait()方法亮垫,JVM會把該線程放入等待池中。(wait會釋放持有的鎖)
(二). 同步阻塞:運行的線程在獲取對象的同步鎖時伟骨,若該同步鎖被別的線程占用饮潦,則JVM會把該線程放入鎖池中。
(三). 其他阻塞:運行的線程執(zhí)行sleep()或join()方法携狭,或者發(fā)出了I/O請求時继蜡,JVM會把該線程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時、join()等待線程終止或者超時稀并、或者I/O處理完畢時鲫剿,線程重新轉(zhuǎn)入就緒狀態(tài)。(注意,sleep是不會釋放持有的鎖) - 死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法稻轨,該線程結(jié)束生命周期。
3.定義和啟動線程
定義線程有兩種方式:
- 實現(xiàn)Runnable接口
- 繼承Thread類
//實現(xiàn)Runnable接口
public class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println("測試");
}
public static void main(String[] args) {
new Thread(new RunnableImpl()).start();
}
}
//繼承Thread類
public class ThreadTest extends Thread {
@Override
public void run() {
System.out.println("測試");
}
public static void main(String[] args) {
new ThreadTest().start();
}
}
啟動線程都是通過調(diào)用Thread.start方法
4.sleep
提供了兩種sleep:
- 指定休眠時間為毫秒(sleep(long millis))
- 指定休眠時間為毫秒+納秒(sleep(long millis, int nanos))
注意:這些睡眠時間并不能保證準(zhǔn)確雕凹,因為它們受底層操作系統(tǒng)提供的設(shè)施的限制殴俱。
5.interrupt
一個中斷是指示線程它應(yīng)該終止它在做什么和做別的事情。由程序員來決定線程是如何響應(yīng)中斷的枚抵,但線程終止是非常常見的线欲。
線程通過interrupt在Thread對象上調(diào)用中斷線程來發(fā)送中斷。為使中斷機(jī)制正常工作汽摹,被中斷的線程必須支持自己的中斷李丰。
中斷狀態(tài)標(biāo)志
中斷機(jī)制通過一個稱為中斷狀態(tài)的內(nèi)部標(biāo)志來實現(xiàn)。調(diào)用Thread.interrupt設(shè)置此標(biāo)志逼泣。當(dāng)線程通過調(diào)用靜態(tài)方法檢查中斷時Thread.interrupted趴泌,中斷狀態(tài)被清除。isInterrupted一個線程用于查詢另一個線程的中斷狀態(tài)的非靜態(tài)方法不會更改中斷狀態(tài)標(biāo)志拉庶。
支持中斷
支持中斷的方式:
- 在捕獲異常后return
- 定期判斷是否中斷嗜憔,是,就return或拋出中斷異常氏仗,然后通過調(diào)用interrupt發(fā)送中斷
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("線程中斷");
return;
}
if(Thread.interrupted()){
System.out.println("線程中斷");
return;
}
if(Thread.interrupted()){
System.out.println("線程中斷");
throw new InterruptedException();
}
6.join
線程A調(diào)用join方法時吉捶,會導(dǎo)致當(dāng)前線程(也就是創(chuàng)建線程A所在的線程)暫停執(zhí)行,直到線程A終止皆尔。
public class ThreadTest extends Thread {
@Override
public void run() {
System.out.println(this.getName()+"加入");
for (int i = 0; i < 4; i++) {
try {
Thread.sleep(1000);
System.out.println(this.getName()+"執(zhí)行");
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("異常");
}
}
System.out.println(this.getName()+"結(jié)束");
}
public ThreadTest(String name) {
super(name);
}
public static void main(String[] args) {
System.out.println("主線程執(zhí)行");
ThreadTest t = new ThreadTest("猴子");
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主線程結(jié)束");
}
}