- 讀《Java高并發(fā)編程詳解》筆記景殷,這本書筆者的收獲很大,配合王文君汪老師的視頻教學基本上可以將線程學的很透徹妖枚,很感謝前輩帶給的這些智慧結(jié)晶运提。以下未我讀本書和看視頻對書的一些摘錄和總結(jié),以及一些補充改含。順序按照書的思路走的情龄。
- 本篇是最基礎的部分,筆者花了很長時間去學習捍壤,看視頻骤视,敲實例,同時對照著java8的官方文檔鹃觉,再點進去學習源碼专酗,旨意是完全搞懂。筆者認為基礎知識學習多久都是值得的盗扇。
1.線程
- 定義:
進程是操作系統(tǒng)動態(tài)執(zhí)行的基本單元祷肯,每一個進程至少要有一個線程運行沉填,線程是執(zhí)行進程的基本單元。
-
線程生命周期:
①. 創(chuàng)建狀態(tài)(New):當線程對象創(chuàng)建后佑笋,即進入創(chuàng)建狀態(tài)翼闹。
new關(guān)鍵字僅為創(chuàng)建一個線程類,在沒有調(diào)用start()方法前允青,它就是一個普通的java類橄碾。
②. 就緒狀態(tài)(Runnable):調(diào)用start()方法,線程即進入就緒狀態(tài)颠锉。處于就緒狀態(tài)的線程法牲,隨時等待cpu調(diào)度執(zhí)行。
當執(zhí)行start()方法后琼掠,才會在jvm中創(chuàng)建線程拒垃,此時線程等待cpu調(diào)度運行。除去意外失望瓷蛙,該狀態(tài)只能進入Running狀態(tài)悼瓮。
③. 運行狀態(tài)(Running):當CPU調(diào)度處于就緒狀態(tài)的線程后,線程才得以執(zhí)行艰猬。
此時線程根據(jù)不同的指令可轉(zhuǎn)換轉(zhuǎn)臺為Runable横堡,Blocked和Dead狀態(tài)。①.cup輪詢調(diào)度和yeild()進入Runable.②.sleep()/wait()/join()方法進入Blocked.③.執(zhí)行完畢進入Dead.
④. 阻塞狀態(tài)(Blocked):處于運行狀態(tài)的線程冠桃,由于原因命贴,暫時放棄對cpu的使用權(quán),停止執(zhí)行食听,此時進入阻塞狀態(tài)胸蛛,直到進入就緒狀態(tài)。
此時線程可轉(zhuǎn)換成Dead和Runable狀態(tài)樱报。①.線程意外死亡進入Dead葬项。②.線程被其他線程notify/notifyall方法喚醒,完成休眠迹蛤,interrupt打斷等進入Runnable.
⑤. 死亡狀態(tài)(Dead):線程執(zhí)行結(jié)束民珍,或異常退出,結(jié)束生命周期笤受。
-
線程的設計模式
3.1. Thread中的模板設計模式
- thread啟動調(diào)用過程
1.當Thread處于Runable狀態(tài)穷缤,此時調(diào)用start()方法啟動線程。
2.start()方法調(diào)用本地方法棧(JNI)中方法start)()箩兽。
3.由JNI的start0()方法調(diào)用Run()方法,執(zhí)行線程邏輯。
4.線程在運行狀態(tài)和死亡狀態(tài)再次調(diào)用start()方法章喉,會拋IllegalThreadStateException異常- 模板設計模式應用
1.由父類抽象出一個模板汗贫,而子類通過重寫該方法而重寫實現(xiàn)具體邏輯身坐,其中父類控制邏輯調(diào)用。
2.模板模式主要由抽象模板(Abstract Template)角色和具體模板(Concrete Template)角色組成落包。父類實現(xiàn)模板方法以final修飾部蛇,子類實現(xiàn)模板方法所控制的具體的操作方法
3.Thread的run和start就是一個模板設計模式的設計。3.2. 使用Runable()接口的策略模式
- Runable接口
1.由于多個線程所實現(xiàn)的run方法控制具體邏輯咐蝇,每次創(chuàng)建線程的時候都需要隱式創(chuàng)建該方法涯鲁,故此java提供一個接口Runnable來將線程的控制和業(yè)務邏輯分離開。
2.創(chuàng)建線程只有一種方式有序,即構(gòu)造Thread類抹腿,而實現(xiàn)現(xiàn)成的執(zhí)行單元有兩種方式,第一種是重寫Thread的run方法旭寿,第二種是實現(xiàn)Runnable接口的run方法警绩,并將Runable接口實例用作構(gòu)造Thread的參數(shù)。
3.策略模式的目的是將線程的控制本身和業(yè)務邏輯的運行分離開盅称,達到職責分明肩祥,功能單一的原則。
4.Thread類的run方法不能共享缩膝,而實現(xiàn)Runnable的實例則可以構(gòu)造不同的Thread實例混狠。
ps:
2.Thread構(gòu)造函數(shù)
- 線程名
1.在構(gòu)造Thread時,可以手動為該線程命名疾层。
2.若創(chuàng)建線程沒有命名将饺,默認以"Thread-"作為前綴與一個以0開始自增的數(shù)字進行組合,這個自增函數(shù)在整個jvm進程中將不斷自增云芦。
3.若同時創(chuàng)建2個線程俯逾,第一個線程使用指定名,第二個線程使用默認名舅逸,則第二個線程以"Thread-1"命名桌肴,即在jvm中沒有一個線程,命名數(shù)字都將自增琉历,不論是否適用該線程默認名坠七。
4.mian()線程的線程名為"mian"。
5.在線程啟動前旗笔,可以通過方法setName()修改線程名彪置,但是啟動后,名字不再被修改蝇恶。
6.靜態(tài)方法:Thread.currentThread().getName() 獲取線程名
- 線程父子關(guān)系
一個線程必然是由另一個線程創(chuàng)建出來的拳魁,而主線程mian是由jvm創(chuàng)建出來的。
- 線程與線程組關(guān)系
1.每一個線程創(chuàng)建的時候撮弧,都會分配線程組潘懊,若構(gòu)造線程的時候姚糊,未顯示的指定線程組,則該線程回默認與其父線程同一線程組授舟。
2.mian線程的線程組名為mian救恨。
3.若子線程與父線程同一個線程組,其與父線程的優(yōu)先級一樣释树。
線程與jvm虛擬機棧
守護線程
1.設置守護線程:setDaemon()
2.設置守護線程在線程的啟動前才會起作用肠槽。可以使用isDaemon判斷該線程是否為守護線程
3.線程死亡后奢啥,設置setDaemon會拋出異常
3.線程API
- sleep方法
1.使用Thread.sleep()會使線程進入Blocked狀態(tài)秸仙,直至休眠完成。
2.jdk1.5以后可以使用更加靈活的枚舉類TimeUnit來替代該方法扫尺。
3.sleep與wait的區(qū)別
?1.sleep是Thread的方法筋栋,休眠是并不釋放資源,不需要定義同步(synchronized)正驻,不需要喚醒弊攘。
?2.wait是Object方法,休眠會釋放資源姑曙,允許其他線程訪問襟交,需要定義同步,需要使用notify()/notifyAll()喚醒伤靠。
- yield方法
1.使用yield方法可以式當前線程從Running狀態(tài)進入Runable.方法不常用捣域。
2.CPU在資源不緊張的情況下會自動忽略該方法。
3.當CPU對該線程執(zhí)行了yield方法宴合,該線程將從新位于調(diào)度隊列中焕梅,和其他線程一樣擁有獲得CPU調(diào)度權(quán)的機會。
4.yield與sleep的區(qū)別:
?1.CPU收到sleep指令后卦洽,線程一定會進入Blocked狀態(tài)贞言,此時該線程仍然占據(jù)資源。
?2.CPU接受到y(tǒng)ield命令后阀蒂,根據(jù)資源使用情況可以選擇不執(zhí)行该窗,若執(zhí)行,則線程釋放資源蚤霞,酗失,進入可執(zhí)行隊列,且該線程可以從新競爭CPU使用權(quán)昧绣。
- 線程優(yōu)先級
1.線程優(yōu)先級范圍(1 value 10)规肴。
2.mian線程優(yōu)先級為5,線程不設置優(yōu)先級,默認為5奏纪。
3.由于優(yōu)先級設置也是一個提示操作(和yield類似)鉴嗤,所以在CPU空閑時斩启,不起作用序调,而對于非root權(quán)限用戶,也會被忽略兔簇。
4.由于優(yōu)先級的特性发绢,所以在設置事務的先后以及重要性上,不要綁定優(yōu)先級垄琐。
5.thread設置優(yōu)先級:setPriority(num)边酒;線程組設計優(yōu)先級:group.setMaXPriority(num)
6.若某線程組中的線程的優(yōu)先級大于線程組的優(yōu)先級,則該線程的優(yōu)先級最大為該線程組優(yōu)先級狸窘。
- interrupt方法
1.調(diào)用interrupt方法會是陷入堵塞(Blocked)狀態(tài)的線程被打斷阻塞墩朦。
2.對于死亡的線程,該方法將被忽略翻擒。
3.每一個線程內(nèi)部都有一個標志氓涣,interrupt flag,來標識當前線程是否被打斷陋气,該標識默認為flag=flase
4.當線程被打斷時劳吠,會拋出InterruptedException異常,可以通過捕獲異常來處理后續(xù)操作巩趁,是否繼續(xù)執(zhí)行該線程和結(jié)束該線程痒玩。
5.使用interrupt方法打斷線程,可以使用isInterrupt()方法(對象方法)议慰,或使用interrupted方法打斷線程(靜態(tài)類方法)方法判斷線程打斷狀況蠢古。
6.使用isInterrupt()方法(對象方法)判斷線程是否被中斷:
?①:若打斷正在執(zhí)行(Running)的線程(未堵塞狀態(tài)),該線程的中斷信號會變?yōu)閠rue别凹,但是該方法并不起作用草讶,線程也不會被打斷Running狀態(tài)。
?②:若打斷正在堵塞狀態(tài)(Blocked)的線程番川,則會拋出InterruptedException異常到涂,線程并不會死亡,是否結(jié)束和處理接下來的邏輯事務看程序的需要颁督,此時中斷信號會變成true,但在拋出異常后恢復為false践啄,程序此時輸出標識為false,避免影響接下來線程方法的調(diào)用沉御。
7.使用interrupted方法打斷線程(靜態(tài)類方法)判斷線程是否被中斷屿讽。情況大致與上述相同,唯一不一樣的是,第二種情況下的伐谈,中斷信號在本次打斷堵塞后一定會變?yōu)閠rue烂完,程序此時第一次輸出標識為true,之后會恢復為false诵棵。僅此區(qū)別而已抠蚣。
- join方法
1.只有該線程啟動后,才能調(diào)用join方法履澳。
2.join方法前啟動的線程嘶窄,無法被join方法約束,只有在join后啟動的線程距贷,會在調(diào)用join方法的線程后執(zhí)行柄冲。
3.某線程執(zhí)行join方法,則該線程所在的主線程main線程會等待執(zhí)行忠蝗,知道主線程中所有的有join方法的線程執(zhí)行完畢现横。
PS:join方法詳解
- 關(guān)閉線程
1.若線程中有執(zhí)行可中斷方法(阻塞等)操作,可以通過捕獲中斷信號來決定是否退出阁最。
2.由于線程標識可能被擦拭戒祠,或者沒有可中斷方法,使用volatile修飾的開關(guān)flag關(guān)閉線程
4.線程同步
- synchronized關(guān)鍵字
①.作用:實現(xiàn)簡單策略防止線程干擾和內(nèi)存一致性錯誤闽撤,若對象對多個線程可見得哆,則對該對象的讀寫將通過線程同步的方式進行。
②.表現(xiàn):某線程獲取與mutex(互斥)關(guān)聯(lián)的monitor(監(jiān)控)鎖哟旗,確保共享變量的互斥訪問贩据,即同一時刻只有一個線程方法同步資源。從而避免數(shù)據(jù)不一致的問題闸餐。
③.synchronized可以對代碼塊或方法進行修飾饱亮,但是不能對class以及變量修飾。
- synchronized本質(zhì)
1.每一個對象都與一個monitor相關(guān)聯(lián)舍沙,該monitor的鎖只能被一個線程同一時間獲取近上,其他線程進入阻塞狀態(tài)。
2.對象的monitor鎖都有一個計數(shù)器拂铡,初始為0壹无,表示未被任何線程獲取,若某線程獲取該鎖后感帅,對計數(shù)器加一斗锭,此時該線程為該對象monitor的所有者。此時其他線程會陷入堵塞狀態(tài)失球,知道m(xù)onitor計數(shù)器變?yōu)?岖是,參與從新競爭該鎖。
3.若已經(jīng)擁有該monitor的線程重入,會導致monitor計數(shù)器再次累加豺撑。
4.當monitor計數(shù)器減為0后烈疚,此時該線程釋放鎖的所有權(quán),并和其他線程再次參數(shù)對鎖的競爭聪轿。
- This Monitor(對象鎖)
1.即某個類中的對象方法或對象方法中的代碼塊被synchronized修飾
2.若同一個類中有多個對象方法或?qū)ο蠓椒ㄖ械拇a塊被synchronized修飾爷肝,若多個線程同時訪問一個該類的實例對象的不同方法,則只有一個線程能夠訪問屹电,因為一個對象實例的對象方法是同一個monitor鎖阶剑。
- Class Monitor(類鎖)
1.即某一個類中有多個靜態(tài)方法或靜態(tài)方法中的代碼塊被synichronized修飾.由于靜態(tài)方法又稱類方法,所以該鎖稱之為類鎖危号,并不是關(guān)鍵字修飾在類上。
2.若同一個類中有多個靜態(tài)方法或靜態(tài)方法中的代碼塊被synichronized修飾素邪,若多個線程同時訪問該類不同靜態(tài)方法外莲,則只有一個線程能夠訪問,因為該類的靜態(tài)方法使用同一個monitor鎖兔朦。
- 死鎖
1.死鎖情況
?①.交叉死鎖偷线,即A線程獲取R1鎖,等待獲取R2鎖沽甥,同時B線程獲取R2鎖声邦,等待獲取R1鎖。
?②.假死死鎖摆舟,CPU占用率升高亥曹,難以檢測。
?②.內(nèi)存不足恨诱,即A媳瞪,B線程執(zhí)行需要占用30內(nèi)存,此時A占據(jù)10照宝,B占據(jù)20蛇受,彼此等待釋放內(nèi)存。
?③.一問一答式數(shù)據(jù)交互厕鹃,客戶端發(fā)送請求兢仰,服務端由于某種原因錯過此時請求,之后客戶端等待回復請求剂碴,服務端也等待請求把将。
?④.數(shù)據(jù)庫鎖,文件鎖汗茄,死循環(huán)引起假死的死鎖
2.死鎖檢測
①.交叉死鎖:一般交叉死鎖會陷入Blocked狀態(tài)秸弛,CPU資源占用不高,很容易借助工具實現(xiàn)。