摘要:多線程環(huán)境下的一些問題安全性問題在沒有正確同步的情況下,多線程環(huán)境下程序可能得出錯誤的結(jié)果。一些相關(guān)概念競爭條件多線程的環(huán)境下,程序執(zhí)行的結(jié)果取決于線程交替執(zhí)行的方式。而線程的交替操作順序是不可預測的,如此程序執(zhí)行的結(jié)果也是不可預測的。
入口
Java多線程的應用復雜性之如jvm有限的幾個內(nèi)存方面的操作和規(guī)范,就像無數(shù)紛繁復雜的應用邏輯建立在有限的指令集上。
如何寫出線程安全的程序,有各種各樣需要遵循的規(guī)則,如果硬是去記憶這些寫法或者規(guī)則,就事倍功半了,最好是先學習原理,抓住問題的主干,再拓展細節(jié),這也是大家公認的學習某種技術(shù)的方式。對于多線程的問題,java使用java內(nèi)存模型 JMM來保證多個線程可以有效地,正確地工作。
學習的步驟可以分為:關(guān)注大師的言行,跟隨大師的舉動——JUC包已經(jīng)足夠豐富,按照API規(guī)范正確使用。
和大師一起修行——理解多線程問題的由來,以及jvm給出的解決方案,需要理解java的內(nèi)存模型JMM,以及JMM給出的線程工作內(nèi)存與主內(nèi)存交互的規(guī)則如何形成JMM的happens-before原則等。參考書有知名的《深入理解Java虛擬機》第12章,最重要的《JSR-133 Java內(nèi)存模型與線程規(guī)范》以及《并發(fā)編程實戰(zhàn)》第16章。
領(lǐng)悟大師的意境——JUC包的實現(xiàn)原理,volatile和CAS構(gòu)筑了JUC包的基礎(chǔ)類,AQS,非阻塞數(shù)據(jù)結(jié)構(gòu),原子變量,這些基礎(chǔ)類又構(gòu)建了JUC包的高層類,Lock,同步器,阻塞隊列,并發(fā)容器,Executor等。理解了高層類的原理,能夠心里有底地使用這些類,構(gòu)建健壯的應用。
成為真正的大師——學習JUC包的實現(xiàn),說不定哪天也能寫出一樣優(yōu)秀的類。
一些背景知識:現(xiàn)代操作系統(tǒng)的線程主要有三種實現(xiàn):內(nèi)核線程實現(xiàn),用戶線程實現(xiàn),混合實現(xiàn)
內(nèi)核線程(KLT):線程表由內(nèi)核維護,由內(nèi)核完成線程的切換,內(nèi)核通過調(diào)度器對線程進行調(diào)度,并將線程的任務(wù)映射到處理器上,每個內(nèi)核線程可以視為內(nèi)核的一個分身。程序一般不會直接使用內(nèi)核線程,而是使用內(nèi)核線程的一種高級接口——輕量級進程(LWP)(廣義上來說,輕量級進程也是在用戶空間的進程中的,所以也是一種用戶線程)。LWP和KLT是一一對應的,是1:1的關(guān)系,因此也叫作一對一線程模型(1:1)。內(nèi)核線程最大的特點就是,如果有輕量級進程發(fā)生了阻塞,不會影響整個進程的工作,內(nèi)核會運行其他可運行的線程。缺點也是明顯的:各種線程操作都需要系統(tǒng)調(diào)用,需要在用戶態(tài)和內(nèi)核態(tài)進行來回切換,代價高昂,而且因為占用內(nèi)核空間,所以內(nèi)核能支持的數(shù)量是有限的。
用戶級線程(UT):狹義上的用戶線程是指,完全建立在用戶空間的線程庫上,由所在進程實現(xiàn)管理的線程。最大的亮點在于可以在不支持多線程的操作系統(tǒng)之上實現(xiàn)多線程,如DOS,同時因為不需要切換到內(nèi)核態(tài),所以快速且低消耗,也能支持更大規(guī)模的線程數(shù)量。這種模型中,一個輕量級進程對應多個線程,因此叫做一對多線程模型(1:N),用戶進程的優(yōu)勢在于不需要內(nèi)核的支援,而因為沒有內(nèi)核的支援,所有的線程操作都需要用戶自己處理,導致復雜性是其劣勢。線程的創(chuàng)建,切換,調(diào)度都是需要考慮的問題,現(xiàn)在使用用戶線程的程序已經(jīng)越來越少了。java線程在JDK1.2之前,使用用戶線程。
用戶線程+輕量級進程的混合實現(xiàn):使用輕量級進程作為用戶線程和內(nèi)核線程的橋梁的一種實現(xiàn),用戶線程和輕量級進程的比例不定,因此也叫多對多線程模型(N:M),UNIX家族中的Solaris提供了N:M的線程模型實現(xiàn)。
更詳細的說明可以查看介紹操作系統(tǒng)的書籍。
jdk1.2 之前,java使用的是稱為“綠色線程”的用戶線程,而在1.2中,線程模型替換為基于操作系統(tǒng)原生線程模型來實現(xiàn)
操作系統(tǒng)支持什么樣的線程模型,很大程度上影響java的線程模型,windows和linux系統(tǒng)提供的線程模型是1:1的,所有這兩個平臺上的JDK使用的是1:1的線程模型,一個java線程映射到一個輕量級進程中,Solaris系統(tǒng)同時支持1:1和N:M,該平臺中的JDK可以指定參數(shù)選擇線程模型。
操作系統(tǒng)的線程特性會對線程的并發(fā)規(guī)模和操作成本產(chǎn)生影響,但是對java程序的編寫和運行來說是透明的。
安全性問題:在沒有正確同步的情況下,多線程環(huán)境下程序可能得出錯誤的結(jié)果。
活躍性問題:在多線程環(huán)境下,當某個操作應該繼續(xù)執(zhí)行卻無法繼續(xù)執(zhí)行下去,就造成了活躍性問題,如:死鎖,饑餓,活鎖。
死鎖:
活鎖:
饑餓:
性能問題:線程的頻繁切換將帶來極大的開銷,如:
保存和恢復執(zhí)行上下文,丟失局部性
使用同步機制的時候,這些機制會抑制某些編譯器優(yōu)化以保證執(zhí)行順序,
如使用volatile保證可見性的情況下,使內(nèi)存緩沖區(qū)中的數(shù)據(jù)無效,其他線程需要重新從主內(nèi)存中加載
所有這些因素會帶來額外的性能開銷。
競爭條件:多線程的環(huán)境下,程序執(zhí)行的結(jié)果取決于線程交替執(zhí)行的方式。而線程的交替操作順序是不可預測的,如此程序執(zhí)行的結(jié)果也是不可預測的。
狀態(tài):狀態(tài)在多線程編程中是一個很核心的概念,因為線程安全性的核心就在于:對可變的共享狀態(tài)的訪問操作進行正確的管理。
非正式的定義:狀態(tài)可以簡單理解為存儲在對象的域中的數(shù)據(jù),下面的Counter類中的count就是一個Counter對象的狀態(tài)。如果不能正確地訪問和修改count,那么count的值就不具備正確性。狀態(tài)也包括一個對象依賴的對象的域。
多線程的環(huán)境下,主要是可變的,共享的狀態(tài)會導致安全性問題,可變意味著狀態(tài)可以被修改,共享意味著可以被多個線程改變,自然而然的,有三種方法來解決這個問題:1.讓對象不可改變 2. 讓狀態(tài)不可共享 3. 必須共享和改變的,使用某種機制來保證順序——同步。
或者更加直接可靠的,不要給對象狀態(tài),一個沒有狀態(tài)的對象一定是線程安全的。
線程安全性:當多個線程訪問某個類的時候,這個類始終能表現(xiàn)正確的行為,那么這個類是線程安全的。
public class Counter { private long count = 0; public long getCount(){ return count; } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/69353.html
摘要:大多數(shù)待遇豐厚的開發(fā)職位都要求開發(fā)者精通多線程技術(shù)并且有豐富的程序開發(fā)調(diào)試優(yōu)化經(jīng)驗,所以線程相關(guān)的問題在面試中經(jīng)常會被提到。將對象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對象稱之為反序列化。 JVM 內(nèi)存溢出實例 - 實戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細介紹 Java 注解的使用,有利于學習編譯時注解 Java 程序員快速上手 Kot...
摘要:學習完多線程之后可以通過下面這些問題檢測自己是否掌握,下面這些問題的答案以及常見多線程知識點的總結(jié)在這里??蛇x數(shù)據(jù)結(jié)構(gòu)與算法如果你想進入大廠的話,我推薦你在學習完基礎(chǔ)或者多線程之后,就開始每天抽出一點時間來學習算法和數(shù)據(jù)結(jié)構(gòu)。 我自己總結(jié)的Java學習的系統(tǒng)知識點以及面試問題,已經(jīng)開源,目前已經(jīng) 35k+ Star。會一直完善下去,歡迎建議和指導,同時也歡迎Star: https://...
摘要:超詳細的面試題總結(jié)一之基本知識多線程和虛擬機創(chuàng)建線程有幾種不同的方式你喜歡哪一種為什么繼承類實現(xiàn)接口應用程序可以使用框架來創(chuàng)建線程池實現(xiàn)接口。死亡線程方法執(zhí)行結(jié)束,或者因異常退出了方法,則該線程結(jié)束生命周期。死亡的線程不可再次復生。 超詳細的Java面試題總結(jié)(一)之Java基本知識 多線程和Java虛擬機 創(chuàng)建線程有幾種不同的方式?你喜歡哪一種?為什么? 繼承Thread類 實現(xiàn)R...
閱讀 3539·2021-11-24 09:39
閱讀 795·2019-08-30 14:22
閱讀 3044·2019-08-30 13:13
閱讀 2330·2019-08-29 17:06
閱讀 2934·2019-08-29 16:22
閱讀 1268·2019-08-29 10:58
閱讀 2441·2019-08-26 13:47
閱讀 1641·2019-08-26 11:39