更新時(shí)間:2019-12-26 09:52:06 來源:動(dòng)力節(jié)點(diǎn) 瀏覽3619次
一段時(shí)間沒有回顧多線程相關(guān)知識(shí)了,雖然工作中會(huì)用到一些多線程的內(nèi)容,但都偏向于基礎(chǔ),今天重讀多線程相關(guān)內(nèi)容,發(fā)現(xiàn)有些東西還是需要注意下。這些一般是面試高頻問題奧。
了解并發(fā)的內(nèi)幕是一個(gè)高級(jí)程序員不可缺少的課程
Java內(nèi)存模型
注意,Java內(nèi)存模型(JMM)和JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)不是同一個(gè)概念,還有一個(gè)概念是Java對(duì)象模型下次可以單獨(dú)拿出來說。
JMM都是圍繞著原子性,可見性,有序性來講的
JMM定義了JVM如何與計(jì)算機(jī)的內(nèi)存進(jìn)行交互
線程對(duì)變量的所有操作都需要在工作內(nèi)存中完成,不可直接操作主內(nèi)存。
內(nèi)存間的交互操作:
Volatile
Volatile可以說是Java虛擬機(jī)內(nèi)提供的最輕量級(jí)同步機(jī)制,其只保證,可見性與有序性,不保證原子性。
可見性:當(dāng)一條線程修改了這個(gè)變量的值,新值對(duì)于其他線程來說是可以立刻得知的,另外兩個(gè)可以實(shí)現(xiàn)可見性的關(guān)鍵字:Synchronized和final
有序性:如果再本線程內(nèi)觀察,所有的操作都是有序的,如果再一個(gè)線程中觀察另外一個(gè)線程,那么所有的操作都是無序的。
Java與線程
并發(fā)不一定依賴多線程,如PHP中常見的多進(jìn)程并發(fā)。Java的Thread類所有關(guān)鍵方法都是聲明為Native的,所以Java并沒有自己實(shí)現(xiàn)線程。
實(shí)現(xiàn)線程的三種方式:使用內(nèi)核線程實(shí)現(xiàn),使用用戶線程實(shí)現(xiàn),和使用用戶線程加更加輕量級(jí)進(jìn)程實(shí)現(xiàn)。
內(nèi)核線程實(shí)現(xiàn)(KLT,Kernel-Level Thread)。程序一般不會(huì)直接使用內(nèi)核線程,而是使用內(nèi)核線程的一種高級(jí)接口,輕量級(jí)進(jìn)程(LWP,Light Weight Process,LWP),先有內(nèi)核線程,才能有輕量級(jí)進(jìn)程。
缺點(diǎn):各種線程操作,如創(chuàng)建,析構(gòu),及同步需要進(jìn)行系統(tǒng)調(diào)用,而系統(tǒng)調(diào)用的代價(jià)比較高,需要在用戶態(tài)和內(nèi)核態(tài)中來回切換。消耗內(nèi)核資源,一個(gè)系統(tǒng)支持輕量級(jí)的進(jìn)程數(shù)量是有限制的。
用戶線程實(shí)現(xiàn),廣義上說,一個(gè)線程只要不是內(nèi)核線程,那就可以任務(wù)是用戶線程。用戶線程完全在用戶態(tài)完成,不用內(nèi)核的幫助,可以支持更大的線程數(shù)量。
缺點(diǎn):沒有內(nèi)核支持,各種操作都比較復(fù)雜?,F(xiàn)在基本棄用了。
用戶線程 + 輕量級(jí)進(jìn)程,綜合兩者的有點(diǎn),用戶進(jìn)程與輕量級(jí)進(jìn)程數(shù)量比是不定的。
線程調(diào)度
協(xié)同式調(diào)度:好處是實(shí)現(xiàn)簡(jiǎn)單,切換操作對(duì)線程自己是可知的,沒有線程同步的問題,線程把自己的事情干完之后才進(jìn)行線程切換。
缺點(diǎn):如果程序編寫不穩(wěn)定,那么系統(tǒng)不可控制。一個(gè)進(jìn)程堅(jiān)持不讓出CPU執(zhí)行實(shí)現(xiàn),就會(huì)導(dǎo)致系統(tǒng)崩潰。
搶占式調(diào)度(Java默認(rèn)調(diào)度):每個(gè)線程由系統(tǒng)來分配執(zhí)行和弦,線程的切換不由線程來決定,當(dāng)一個(gè)進(jìn)程出現(xiàn)問題,系統(tǒng)可以殺掉這個(gè)進(jìn)程。
注意:并不是線程的優(yōu)先級(jí)越高,線程就一定會(huì)優(yōu)先執(zhí)行,只是說優(yōu)先級(jí)高的線程更可能被選擇到。
Java線程狀態(tài)轉(zhuǎn)換
貼一張圖,好好記:
線程安全的實(shí)現(xiàn)方法
互斥同步,加鎖,悲觀方案,保證共享數(shù)據(jù)同一時(shí)刻只有一個(gè)線程訪問。,互斥是因,同步是果。
非阻塞同步,CAS,樂觀方案,先進(jìn)行操作,如果沒有其他線程也進(jìn)行操作,那么就操作成功了,如果有其它線程也在操作共享數(shù)據(jù),那么再重試。
無同步方案,一般為純代碼,有一些特性,如不依賴堆上的公用系統(tǒng)資源
鎖優(yōu)化
自旋鎖與自適應(yīng)自旋
假如共享數(shù)據(jù)只會(huì)持續(xù)很短的一段時(shí)間,為了這段時(shí)間進(jìn)行掛起和恢復(fù)線程并不值得,這時(shí)我們可以讓后面請(qǐng)求鎖的線程稍等一下,讓線程進(jìn)行一個(gè)忙循環(huán)(自旋),這就是所謂的自旋鎖。
因?yàn)閭冇袝r(shí)不值得共享數(shù)據(jù)到底被鎖了多久,盲目的自旋可能導(dǎo)致性能的損失,JDK1.6之后,系統(tǒng)引入了自適應(yīng)的自旋,及在一次共享數(shù)據(jù)被鎖定時(shí),加入系統(tǒng)多次獲得自旋鎖,系統(tǒng)可以允許線程自旋的次數(shù)更多時(shí)間更久一些。如果多次沒有獲得自旋鎖,那么系統(tǒng)下次可能會(huì)省略掉自旋鎖。
鎖消除
對(duì)一些不可能存在共享數(shù)據(jù)競(jìng)爭(zhēng)的鎖進(jìn)行消除。
鎖粗化
有時(shí)候多個(gè)操作都對(duì)同一個(gè)對(duì)象加鎖,頻繁的加鎖也會(huì)影響性能,那么系統(tǒng)就把鎖的同步范圍進(jìn)行擴(kuò)展。如StringBuffer()的多個(gè)append操作。
偏向鎖
可以理解為偏袒鎖,鎖會(huì)偏向于第一個(gè)獲得它的線程,如果接下來的執(zhí)行過程中,該鎖沒有被其他線程獲取,則持有偏向鎖的線程將永遠(yuǎn)不在需要進(jìn)行同步。
以上就是動(dòng)力節(jié)點(diǎn)Java培訓(xùn)機(jī)構(gòu)小編介紹的“Java高級(jí)程序員必備的內(nèi)容知識(shí)”的內(nèi)容,希望對(duì)大家有幫助,如有疑問,請(qǐng)?jiān)诰€咨詢,有專業(yè)老師隨時(shí)為你服務(wù)。
Java全套自學(xué)資料+視頻
Java自學(xué)視頻教程(免費(fèi)學(xué)習(xí)):http://www.dabaquan.cn/video.html
Java技術(shù)教程:http://www.dabaquan.cn/tutorial/
相關(guān)內(nèi)容
相關(guān)閱讀
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743