摘要:線程的生命周期線程的生命周期大致可以分為下面五種狀態(tài)新建狀態(tài)就緒狀態(tài)運行狀態(tài)休眠狀態(tài)終止狀態(tài)新建狀態(tài),是線程被創(chuàng)建且未啟動的狀態(tài)這里的創(chuàng)建,僅僅是在的這種編程語言層面被創(chuàng)建,而在操作系統(tǒng)層面,真正的線程還沒有被創(chuàng)建。
概要
目前CPU的運算速度已經(jīng)達到了百億次每秒,甚至更高的量級,家用電腦即使維持操作系統(tǒng)正常運行的進程也會有數(shù)十個,線程更是數(shù)以百計。
線程是CPU的調(diào)度和分派的基本單位,為了更充分地利用CPU資源以及提高生產(chǎn)率和高效地完成任務(wù),在現(xiàn)實場景中一般都會采用多線程處理。
線程的生命周期線程的生命周期大致可以分為下面五種狀態(tài):New(新建狀態(tài))、RUNABLE(就緒狀態(tài))、RUNNING(運行狀態(tài))、休眠狀態(tài)、DEAD(終止狀態(tài))
1、新建狀態(tài),是線程被創(chuàng)建且未啟動的狀態(tài);這里的創(chuàng)建,僅僅是在JAVA的這種編程語言層面被創(chuàng)建,而在操作系統(tǒng)層面,真正的線程還沒有被創(chuàng)建。
Thread t1 = new Thread()
2、就緒狀態(tài),指的是調(diào)用start()方法之后,線程等待分配給CPU執(zhí)行(這時候,線程已經(jīng)在操作系統(tǒng)層面被創(chuàng)建)
t1.start()
3、運行狀態(tài),當CPU空閑時,線程被分得CPU時間片,執(zhí)行Run()方法的狀態(tài)
4、休眠狀態(tài),運行狀態(tài)的線程,如果調(diào)用一個阻塞的API或者等待某個事件,那么線程的狀態(tài)就會轉(zhuǎn)換到休眠狀態(tài),一般有以下幾種情況
同步阻塞:鎖被其它線程占用
主動阻塞:調(diào)用Thread的某些方法,主動讓出CPU執(zhí)行權(quán),比如:sleep()、join()等方法
等待阻塞:執(zhí)行了wait()方法
5、終止狀態(tài),線程執(zhí)行完(run()方法執(zhí)行結(jié)束)或者出現(xiàn)異常就會進入終止狀態(tài)
對應(yīng)的是JAVA中Thread類State中的六種狀態(tài)
public class Thread implements Runnable { //......... public enum State { NEW, // 初始化狀態(tài) RUNNABLE, // 可運行/運行狀態(tài) BLOCKED, // 阻塞狀態(tài) WAITING, // 無時限等待 TIMED_WAITING, // 有時限等待 TERMINATED; // 終止狀態(tài) } // .......... }休眠狀態(tài)(BLOCKED、WAITING、TIMED_WAITING)與RUNNING狀態(tài)的轉(zhuǎn)換
1、RUNNING狀態(tài)與BLOCKED狀態(tài)的轉(zhuǎn)換
線程等待 synchronized 的隱式鎖,RUNNING —> BLOCKED
線程獲得 synchronized 的隱式鎖,BLOCKED —> RUNNING
2、RUNNING狀態(tài)與WAITING狀態(tài)的轉(zhuǎn)換
獲得 synchronized 隱式鎖的線程,調(diào)用無參數(shù)的Object.wait()方法
調(diào)用無參數(shù)Thread.join()方法
調(diào)用LockSupport.park()方法,線程阻塞切換到WAITING狀態(tài),
調(diào)用LockSupport.unpark()方法,可喚醒線程,從WAITING狀態(tài)切換到RUNNING狀態(tài)
3、RUNNING狀態(tài)與TIMED_WAITING狀態(tài)的轉(zhuǎn)換
調(diào)用帶超時參數(shù)的 Thread..sleep(long millis)方法
獲得 synchronized 隱式鎖的線程,調(diào)用帶超時參數(shù)的Object.wait(long timeout)方法
調(diào)用帶超時參數(shù)的Thread.join(long millis)方法
調(diào)用帶超時參數(shù)的LockSupport.parkNanos(Object blocker,long deadline)方法
調(diào)用帶超時參數(shù)的LockSupport.parkUntil(long deadline)方法
廢棄掉的線程方法 :stop()、suspend()、resume()stop()方法,會真正的殺死線程,不給線程任何喘息的機會,假設(shè)獲得 synchronized 隱式鎖的線程,此刻執(zhí)行stop()方法,該鎖不會被釋放,導(dǎo)致其它線程沒有任何機會獲得鎖,顯然這樣的結(jié)果不是我們想要見到的。
suspend() 和 resume()方法同樣,因為某種不可預(yù)料的原因,已經(jīng)被建議不在使用
不能使用stop()、suspend() 、resume() 這些方法來終止線程或者喚醒線程,那么我們應(yīng)該使用什么方法來做呢?答案是:優(yōu)雅的使用Thread.interrupt()方法來做
優(yōu)雅的Thread.interrupt()方法中斷線程interrupt() 方法僅僅是通知線程,線程有機會執(zhí)行一些后續(xù)操作,同時也可以無視這個通知,這個方法通過修改了調(diào)用線程的中斷狀態(tài)來告知那個線程,說它被中斷了,線程可以通過isInterrupted() 方法,檢測是不是自己被中斷。
當線程被阻塞的時候,比如被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞時;調(diào)用它的interrput()方法,會產(chǎn)生InterruptedException異常。
擴展知識點探秘局部變量不會引發(fā)并發(fā)問題的原因
在Java領(lǐng)域,線程可以擁有自己的操作數(shù)棧,程序計數(shù)器、局部變量表等資源;我們都知道,多個線程同時訪問共享變量的時候,會導(dǎo)致數(shù)據(jù)不一致性等并發(fā)問題;但是 Java 方法里面的局部變量是不存在并發(fā)問題的,具體為什么呢?我們先來了解一下這些基礎(chǔ)知識。
局部變量的作用域是方法內(nèi)部的,當方法執(zhí)行完了,局部變量也就銷毀了,也就是說局部變量應(yīng)該是和方法同生共死的。
Java中的方法是如何調(diào)用的?當調(diào)用方法時,會創(chuàng)建新的棧幀,并壓入調(diào)用棧;當方法返回時,對應(yīng)的棧幀就會被自動彈出。也就是說,棧幀和方法是同生共死的。
從上面我們可以得出:方法的調(diào)用就是壓棧和出棧的過程,而在Java中的方法的局部變量又是存儲在棧幀中,所以我們用下面的示意圖幫助大家理解一下
說了那么多,我們還沒有解釋局部變量為啥不會產(chǎn)生并發(fā)問題,以上,我們知道了,方法的調(diào)用是壓棧和出棧(棧幀)的過程,局部變量又存儲在棧幀中。那么我們的線程和調(diào)用棧又有什么關(guān)系呢,答案是:每個線程都有自己獨立的調(diào)用棧
到現(xiàn)在,相信大家都已經(jīng)明白了,局部變量之所以不存在并發(fā)問題,是因為,每個線程都有自己的調(diào)用棧,局部變量都保存在線程各自的調(diào)用棧里面,沒有共享,自然就不存在并發(fā)問題。
歡迎大家關(guān)注公眾號:小白程序之路(whiteontheroad),第一時間獲取最新信息?。?!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74013.html
摘要:在領(lǐng)域,實現(xiàn)并發(fā)程序的主要手段就是多線程??蛇\行狀態(tài)指的是線程可以分配執(zhí)行。當?shù)却氖录霈F(xiàn)了,線程就會從休眠狀態(tài)轉(zhuǎn)換到可運行狀態(tài)。導(dǎo)出線程棧,分析線程狀態(tài)是診斷并發(fā)問題的一個重要工具。 在 Java 領(lǐng)域,實現(xiàn)并發(fā)程序的主要手段就是多線程。線程是操作系統(tǒng)里的一個概念,雖然各種不同的開發(fā)語言如 Java、C# 等都對其進行了封裝,但原理和思路都是相同都。Java 語言里的線程本質(zhì)上就是...
摘要:線程中斷線程中斷就是一種協(xié)作機制。它并不會真正的中斷一個正在運行的線程,而只是發(fā)出中斷請求,然后由線程在下一個合適的時刻中斷自己。 線程池生命周期包括: RUNNING:接收新的任務(wù)并處理隊列中的任務(wù) SHUTDOWN:不接收新的任務(wù),但是處理隊列中的任務(wù) STOP:不接收新的任務(wù),不處理隊列中的任務(wù),同時中斷處理中的任務(wù) TIDYING:所有的任務(wù)處理完成,有效的線程數(shù)是0 TER...
摘要:就緒狀態(tài)調(diào)用或者由阻塞狀態(tài)被解除時,進入就緒狀態(tài),此時,只能表示線程可以運行了,但不代表已經(jīng)運行了,需要等待的調(diào)度。死亡狀態(tài)當線程執(zhí)行結(jié)束或者異常等,線程就會結(jié)束,進入死亡狀態(tài)。 流程圖 showImg(https://segmentfault.com/img/bVbuJ6f); 新建狀態(tài) 當用new創(chuàng)建一個線程后,線程就處于新建狀態(tài),此時和其他普通java對象一樣,由JVM創(chuàng)建內(nèi)存空...
摘要:定義等待該線程終止,比如線程調(diào)用了線程的,那么線程要等到線程執(zhí)行完后,才可以繼續(xù)執(zhí)行。 定義 等待該線程終止,比如A線程調(diào)用了B線程的join,那么A線程要等到B線程執(zhí)行完后,才可以繼續(xù)執(zhí)行。 示例 public class JoinDemo { static class JoinThread1 implements Runnable { Thread thre...
閱讀 3422·2021-11-24 09:39
閱讀 1809·2021-11-17 09:33
閱讀 3541·2021-10-12 10:12
閱讀 5044·2021-09-22 15:51
閱讀 1122·2019-08-30 13:11
閱讀 3584·2019-08-30 10:59
閱讀 576·2019-08-30 10:48
閱讀 1323·2019-08-26 13:48