通用的線程生命周期
- 五態(tài)模型: 初始狀態(tài)牍颈、可運行狀態(tài)、運行狀態(tài)谍肤、休眠狀態(tài)啦租、終止狀態(tài)
- 初始狀態(tài):指的線程已經(jīng)被創(chuàng)建,但是還不允許分配的CPU執(zhí)行荒揣。僅僅只編程語言層面被創(chuàng)建篷角,而在操作系統(tǒng)層面,真正的線程還沒有創(chuàng)建系任。
- 可運行狀態(tài): 指的是線程可以分配CPU執(zhí)行恳蹲。此時操作系統(tǒng)線程已經(jīng)被成功創(chuàng)建了,所以可以分配CPU執(zhí)行俩滥。
- 當有空間CPU時嘉蕾,操作系統(tǒng)會將其分配給一個處于可運行狀態(tài)的線程。被分配到CPU的線程的狀態(tài)就轉(zhuǎn)換成了運行狀態(tài)霜旧。
- 運行狀態(tài)的線程如果調(diào)用一個阻塞API或者等待某個事件错忱,此時線程的狀態(tài)就會轉(zhuǎn)換到了休眠狀態(tài),同時釋放CPU使用權(quán)挂据,休眠狀態(tài)的線程永遠沒有機會獲得CPU使用權(quán)航背。當?shù)却臅r間出現(xiàn)了,線程就會從休眠狀態(tài)轉(zhuǎn)換到可運行狀態(tài)棱貌。
- 線程執(zhí)行完或者出現(xiàn)異常就會進入終止狀態(tài)玖媚。就行終止狀態(tài)也就意味著線程的生命周期結(jié)束了
Java中線程的生命周期
- NEW(初始化狀態(tài))
- RUNNABLE(可運行/運行狀態(tài))
- BLOCKED(阻塞狀態(tài))
- WAITING(無時限等待)
- TERMINATED(終止狀態(tài))
各個狀態(tài)的轉(zhuǎn)換:
- RUNNABLE與BLOCKED狀態(tài)轉(zhuǎn)換
- synchronized
- RUNNABLE與WAITING的狀態(tài)轉(zhuǎn)換
-
有三種場景會觸發(fā)轉(zhuǎn)換:
- 獲得synchronized 隱式鎖的線程,調(diào)用了無參數(shù)的Object.wait()方法
- 調(diào)用了Thread.join()方法婚脱。其中join()是一種線程同步方法今魔,例如一個線程Thread A,當調(diào)用A.join()的時候障贸,執(zhí)行這條語句的線程會等待thread A執(zhí)行完错森,而等待中的這個線程,其狀態(tài)會從RUNNABLE轉(zhuǎn)換到WAITING.當線程thread A執(zhí)行完篮洁,原來等待它的線程又從WAITING狀態(tài)裝換到RUNNABLE涩维。
- LockSupport.park()方法。java并發(fā)包中的鎖,都是基于LockSupport對象實現(xiàn)的瓦阐。調(diào)用LockSupport()方法蜗侈,當前線程會阻塞,線程的狀態(tài)會從RUNNABLE轉(zhuǎn)換到WAITING睡蟋。調(diào)用LockSupport.unpark(Thread thread)可喚醒目標線程踏幻,目標線程的狀態(tài)又從WAITING狀態(tài)轉(zhuǎn)換到RUNNABLE。
- RUNNABLE與TIMED_WAITING的狀態(tài)轉(zhuǎn)換
- 五種場景觸發(fā)這種轉(zhuǎn)換:
- 調(diào)用帶超時參數(shù)的Thread.sleep(long millis)方法
- 獲得synchronized隱式鎖的線程戳杀,調(diào)用帶超時參數(shù)的Object.wait(long timeout)方法
- 調(diào)用帶超時參數(shù)的Thead.join(long millis)方法
- 調(diào)用帶超時參數(shù)的LockSupport.parkNanos(Object blocker,long deadline)方法
- 調(diào)用帶超時參數(shù)的LockSupport.parkUntil(long deadline)方法该面。
- 從NEW到RUNNABLE狀態(tài)
- 兩種創(chuàng)建線程的方式
- 當線程被NEW出來以后,調(diào)用start()后才會從NEW轉(zhuǎn)換到RUNNABLE
- 從RUNNABLE 到 TERMINATED狀態(tài)
- 線程執(zhí)行完run()方法后信卡,會自動轉(zhuǎn)換到TERMINATED狀態(tài)隔缀,當如果執(zhí)行run()方法時拋出異常,也會線程終止
- stop()和interrupt()方法的主要區(qū)別傍菇?
- stop():stop()方法會真的殺死線程蚕泽,不給線程喘息的機會,如果線程持有ReentrantLock鎖桥嗤,被stop()的線程并不會自動調(diào)用ReentrantLock的unlock()去釋放鎖,那其他線程就再也沒有機會獲得ReentrantLock鎖仔蝌,這很危險泛领。所以stop()/suspend()/resume()方法,都不建議使用
- interrput():interrupt()方法僅僅是通知線程敛惊,線程有機會執(zhí)行一些后續(xù)的操作渊鞋,同時也可以無視這個通知。被interrupt的線程瞧挤,是怎么收到通知的呢锡宋?一種是異常,另一種是主動檢測特恬。
-
異常:
- 當線程A處于WAITING执俩、TIMED_WAITING狀態(tài)時,如果其他線程調(diào)用線程A的interrupt()方法癌刽,會使線程A返回RUNNABLE狀態(tài)役首,同時線程A的代碼會觸發(fā)InterruptedException異常。WAITING显拜、TIMED_WAITING狀態(tài)的觸發(fā)條件都是調(diào)用了類似wait()衡奥、join()、sleep()這樣的方法远荠,這些方法的簽名矮固,發(fā)現(xiàn)都會throws InterruptedException這個異常。這個異常的觸發(fā)條件就是:其他線程調(diào)用了該線程的interrupt()方法.
- 當線程A處于RUNNABLE狀態(tài)譬淳,并且阻塞在java.nio.channels.InterruptibleChannedl上時档址,如果其他線程調(diào)用線程A的interrupt()方法盹兢,線程A會觸發(fā)java.nio.channels.ClosedByInterruptExecption這個異常;而阻塞在java.nio.channels.Selector上時辰晕,如果其他線程調(diào)用A的interrupt()方法蛤迎,線程A的java.nio.channels.Selector會立即返回。
主動檢測:
如果線程處于RUNNABLE狀態(tài)含友,并且沒有阻塞在某個I/O操作上替裆,,例如中斷就散圓周率的線程A窘问,這時就得依賴A主動檢測人中斷狀態(tài)了辆童。如果其他線程調(diào)用了A的interrupt()方法,那么線程A可以通過isInterrupt()方法惠赫,檢測是不是自己中斷了把鉴。