走進(jìn)Java世界中的線程
start方法調(diào)用結(jié)束并不意味著相應(yīng)的線程已經(jīng)開始運(yùn)行,運(yùn)行時(shí)間有線程調(diào)度器決定
運(yùn)行結(jié)束的線程所占用的資源(如內(nèi)存空間)會(huì)如同其他Java對象一樣被JVM虛擬機(jī)垃圾回收
為什么不直接調(diào)用run方法?
如果在某處代碼中直接調(diào)用某個(gè)線程的run方法,那么這個(gè)線程的run方法將在當(dāng)前線程中運(yùn)行,而不是在其自身線程中運(yùn)行,違背了創(chuàng)建線程的初衷。
但是,確實(shí)是允許直接調(diào)用run方法的。
Thread類實(shí)現(xiàn)了Runnable接口
兩種創(chuàng)建線程方式的比較:
繼承方式和接口方式,后者屬于組合的技術(shù),耦合性更低
后者的一個(gè)Runnable實(shí)例可以被多個(gè)線程實(shí)例共享
繼承的方式創(chuàng)建線程,Java虛擬機(jī)會(huì)為其分配調(diào)用棧空間、內(nèi)核線程等資源,成本更加昂貴
線程饑餓:
某些線程永遠(yuǎn)得不到運(yùn)行機(jī)會(huì),可能由于優(yōu)先級使用不當(dāng)導(dǎo)致。
守護(hù)線程和用戶線程:
用戶線程會(huì)阻止Java虛擬機(jī)的正常停止,一個(gè)Java虛擬機(jī)只有在其所有的用戶線程都運(yùn)行結(jié)束后才能正常停止;
守護(hù)線程則不會(huì)影響,一般用來執(zhí)行一些重要性不是很高的任務(wù),例如用于監(jiān)視其它線程的運(yùn)行情況。
通常情況下,一個(gè)線程是否是守護(hù)線程或者是用戶線程,和其父線程保持一致。
工作線程(后臺(tái)線程):
通常是其父類線程創(chuàng)建來用于專門執(zhí)行某項(xiàng)特定任務(wù)的線程;
多線程編程的優(yōu)勢:
提高系統(tǒng)的吞吐率
提高響應(yīng)性
充分利用多喝處理器資源
最小化對系統(tǒng)資源的使用
簡化程序的結(jié)構(gòu)
多線程編程的風(fēng)險(xiǎn):
線程安全
線程活性
死鎖
活鎖:一個(gè)線程一直在嘗試某個(gè)操作但就是沒有進(jìn)展
上下文切換
這是屬于額外的資源消耗
可靠性
多線程編程的目標(biāo)與挑戰(zhàn)
串行、并發(fā)和并行
串行:按照順序執(zhí)行
并發(fā):宏觀上是同時(shí)進(jìn)行,微觀上輪流進(jìn)行
并行:嚴(yán)格同時(shí)進(jìn)行
多線程編程的實(shí)質(zhì)就是將任務(wù)的處理方式由串行改為并發(fā),即實(shí)現(xiàn)并發(fā)化,以發(fā)揮并發(fā)的優(yōu)勢。
競態(tài)
一個(gè)計(jì)算結(jié)果的正確性與實(shí)踐有關(guān)的現(xiàn)象,表現(xiàn)為一個(gè)問題,對于同樣的輸入,程序的輸出有時(shí)候正確,有時(shí)候錯(cuò)誤。
舉例:多個(gè)線程對共享變量,進(jìn)行i++操作
嚴(yán)格定義:
競態(tài)(Race Condition)是指計(jì)算結(jié)果的正確性依賴于相對時(shí)間順序或者線程的交錯(cuò)。
注意:競態(tài)不一定就導(dǎo)致計(jì)算結(jié)果的不正確,它只是不排除計(jì)算結(jié)果時(shí)而正確,時(shí)而錯(cuò)誤的可能。
原子性
對于涉及到共享變量訪問的操作,若該操作從執(zhí)行線程以外的任意線程來看是不可分割的,那么該操作就是原子操作,該操作具有原子性
即,其它線程不會(huì)“看到”該操作執(zhí)行了部分的中間結(jié)果
Java中實(shí)現(xiàn)原子性的兩種操作:
鎖(Lock)
CAS(Compare-and-Swap)指令,俗稱硬件鎖
volatile關(guān)鍵字:
僅僅能保證變量寫操作的原子性,不能保證讀寫操作的原子性
所以我們一般說,volatile只能保證可見性,不保證原子性。
可見性
多線程環(huán)境下,一個(gè)線程對于某個(gè)共享變量的更新,后續(xù)訪問該變量的線程可能無法立刻讀取到這個(gè)更新的結(jié)果,這就是不可見的情況。
可見性就是指一個(gè)線程對共享變量的更新的結(jié)果對于讀取相應(yīng)共享變量的線程而言是否可見的問題
可見性和原子性的聯(lián)系和區(qū)別:
原子性描述的是一個(gè)線程對共享變量的更新,從另一個(gè)線程的角度來看,它要么完成,要么尚未發(fā)生。
可見性描述一個(gè)線程對共享變量的更新對于另一個(gè)線程而言是否可見
重排序:
重排序舉例
-new Instance()到底發(fā)生了什么?
- 分配對象的內(nèi)存空間
- 初始化對象instance
- 設(shè)置instance指向剛分配的內(nèi)存地址
- 2和3可能發(fā)生重排序
重排序可能導(dǎo)致線程安全問題
重排序不是必然出現(xiàn)的
上下文切換:
一個(gè)線程被暫停,即被剝奪處理器的使用權(quán),另外一個(gè)線程被選中開始或者繼續(xù)運(yùn)行的過程就叫做線程上下文切換
線程的活性故障:
死鎖(Deadlock)
鎖死(Lockout)
活鎖(Livelock)
饑餓(Starvation)
資源爭用和調(diào)度
公平調(diào)度策略:
按照申請的先后順序進(jìn)行授予資源的獨(dú)占權(quán)
非公平調(diào)度策略:
沒有按照先后順序授予資源的獨(dú)占權(quán)
非公平調(diào)度的解釋:
在該策略中,資源的持有線程釋放該資源的時(shí)候,等待隊(duì)列中一個(gè)線程會(huì)被喚醒,而該線程從被喚醒到其繼續(xù)執(zhí)行可能需要一段時(shí)間。在該事件內(nèi),新來的線程(活躍線程)可以先被授予該資源的獨(dú)占權(quán)。
如果新來的線程占用該資源的時(shí)間不長,那么它完全有可能在背喚醒的線程繼續(xù)執(zhí)行前釋放相應(yīng)的資源,從而不影響該被喚醒的線程申請資源。
非公平調(diào)度策略和公平調(diào)度策略的優(yōu)缺點(diǎn)分析:
非公平調(diào)度策略:
優(yōu)點(diǎn):前者吞吐率較高,即單位時(shí)間內(nèi)可以為更多的申請者調(diào)配資源;
缺點(diǎn):資源申請者申請資源所需的時(shí)間偏差可能較大,并可能出現(xiàn)線程饑餓的現(xiàn)象
公平調(diào)度策略:
優(yōu)點(diǎn):適合在資源的持有線程占用資源的時(shí)間相對長或者資源的平均申請時(shí)間間隔相對長的情況下,或者對資源申請所需的時(shí)間偏差有所要求的情況下使用;線程申請資源所需的時(shí)間偏差較小;不會(huì)出現(xiàn)線程饑餓的現(xiàn)象
缺點(diǎn):吞吐率較小
如果對你有幫助,記得點(diǎn)贊哦~歡迎大家關(guān)注我的博客,我會(huì)持續(xù)更新后續(xù)章節(jié)學(xué)習(xí)筆記,可以點(diǎn)擊原文鏈接更多精彩內(nèi)容等著你
http://blog.sina.com.cn/s/blog_16963d3590102xe8b.html