線程的生命周期
Java語言中定義了5種線程狀態(tài),在任意一個時間點,一個線程只能有且只有其中一種狀態(tài),這5種狀態(tài)是:
- 新建(New):創(chuàng)建后尚未啟動的線程處于這種狀態(tài)。
- 運行(Runable):包括了操作系統(tǒng)線程狀態(tài)中的Running和Ready,也就是處于此狀態(tài)的線程有可能正在執(zhí)行,也有可能正在等待著CPU為它分配執(zhí)行時間。
- 無限期等待(Waiting):處于這種狀態(tài)的線程不會被分配CPU執(zhí)行時間,它們要等待被其他線程顯式地喚醒。以下方法會讓線程陷入無限期的等待狀態(tài):
- 沒有設(shè)置timeout參數(shù)的Object.wait()方法;
- 沒有設(shè)置timeout參數(shù)的Thread.join()方法;
- LockSupport.park()方法;
- 限期等待(Timed Waiting):處于這種狀態(tài)的線程也不會被分配CPU執(zhí)行時間,不過無須等待被其他線程顯式地喚醒,在一定時間之后它們會由操作系統(tǒng)自動喚醒。以下方法會讓線程進入限期等待狀態(tài):
- Thread.sleep()方法;
- 設(shè)置了timeout參數(shù)的Object.wait()方法;
- 設(shè)置了timeout參數(shù)的Thread.join()方法;
- LockSupport.parkNanos()方法;
- LockSupport.parkUntil()方法;
- 阻塞(Blocked):線程被阻塞了,“阻塞狀態(tài)”與“等待狀態(tài)”的區(qū)別是:“阻塞狀態(tài)”在等待著獲取到一個排它鎖,這個事件將在另外一個線程放棄這個鎖的時候發(fā)生;而“等待狀態(tài)”則是在等待一段時間,或者喚醒動作的發(fā)生。在程序等待進入同步區(qū)域(synchronized)的時候,線程將進入這種狀態(tài)。
- 結(jié)束(Terminated):已終止的線程狀態(tài),線程已經(jīng)結(jié)束執(zhí)行。
線程間的狀態(tài)轉(zhuǎn)換
1、新建(New)
新創(chuàng)建了一個線程對象,還未調(diào)用start()方法。
Thread thread = new Thread();
2、就緒(Ready)
線程對象創(chuàng)建后,其他線程(比如main線程)調(diào)用了該對象的start()方法。該狀態(tài)的線程位于可運行線程池中,等待被線程調(diào)度選中 獲取cpu 的使用權(quán) 。
3、運行中(Running)
可運行狀態(tài)(runnable)的線程獲得了cpu 時間片(timeslice) ,執(zhí)行程序代碼。
4、限期等待(Timed Waiting)
也可以稱作 TIMED_WAITING(有等待時間的等待狀態(tài))。
線程主動調(diào)用以下方法:
- Thread.sleep方法;
- Object的wait方法,帶有時間;
- Thread.join方法,帶有時間;
- LockSupport的parkNanos方法,帶有時間。
5、無限期等待(Waiting)
運行中(Running)的線程執(zhí)行了以下方法:
- Object的wait方法,并且沒有使用timeout參數(shù);
- Thread的join方法,沒有使用timeout參數(shù);
- LockSupport的park方法;
- Conditon的await方法。
6、阻塞(Blocked)
阻塞狀態(tài)是指線程因為某種原因放棄了cpu 使用權(quán),暫時停止運行。直到線程進入可運行(runnable)狀態(tài),才有機會再次獲得cpu timeslice 轉(zhuǎn)到運行(running)狀態(tài)。阻塞的情況分兩種:
- 同步阻塞:運行(running)的線程進入了一個synchronized方法,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池(lock pool)中。
- 其他阻塞:運行(running)的線程發(fā)出了I/O請求時,JVM會把該線程置為阻塞狀態(tài)。當I/O處理完畢時,線程重新轉(zhuǎn)入可運行(runnable)狀態(tài)。
7、結(jié)束(Terminated)
線程run()、main() 方法執(zhí)行結(jié)束,或者因異常退出了run()方法,則該線程結(jié)束生命周期。