總結(jié)了線程安全性的二十四個精華問題

      網(wǎng)友投稿 838 2025-04-01

      1、對象的狀態(tài):對象的狀態(tài)是指存儲在狀態(tài)變量中的數(shù)據(jù),對象的狀態(tài)可能包括其他依賴對象的域。在對象的狀態(tài)中包含了任何可能影響其外部可見行為的數(shù)據(jù)。

      2、一個對象是否是線程安全的,取決于它是否被多個線程訪問。這指的是在程序中訪問對象的方式,而不是對象要實現(xiàn)的功能。當(dāng)多個線程訪問某個狀態(tài)變量并且其中有一個線程執(zhí)行寫入操作時,必須采用同步機(jī)制來協(xié)同這些線程對變量的訪問。同步機(jī)制包括synchronized、volatile變量、顯式鎖、原子變量。

      3、有三種方式可以修復(fù)線程安全問題:

      1)不在線程之間共享該狀態(tài)變量

      2)將狀態(tài)變量修改為不可變的變量

      3)在訪問狀態(tài)變量時使用同步

      4、線程安全性的定義:當(dāng)多個線程訪問某個類時,不管運行時環(huán)境采用何種調(diào)度方式或者這些線程將如何交替執(zhí)行,并且在主調(diào)代碼中不需要任何額外的同步,這個類都能表現(xiàn)出正確的行為,那么就稱這個類是線程安全的。

      5、無狀態(tài)變量一定是線程安全的,比如局部變量。

      6、讀取-修改-寫入操作序列,如果是后續(xù)操作是依賴于之前讀取的值,那么這個序列必須是串行執(zhí)行的。在并發(fā)編程中,由于不恰當(dāng)?shù)膱?zhí)行時序而出現(xiàn)不正確的結(jié)果是一種非常重要的情況,它稱為競態(tài)條件(Race Condition)。最常見的競態(tài)條件類型就是先檢查后執(zhí)行的操作,通過一個可能失效的觀測結(jié)果來決定下一步的操作。

      7、復(fù)合操作:要避免競態(tài)條件問題,就必須在某個線程修改該變量時,通過某種方式防止其他線程使用這個變量,從而確保其他線程只能在修改操作完成之前或之后讀取和修改狀態(tài),而不是在修改狀態(tài)的過程中。假定有兩個操作A和B,如果從執(zhí)行A的線程看,當(dāng)另一個線程執(zhí)行B時,要么將B全部執(zhí)行完,要么完全不執(zhí)行B,那么A和B對彼此來說就是原子的。原子操作是指,對于訪問同一個狀態(tài)的所有操作來說,這個操作是一個以原子方式執(zhí)行的操作。

      為了確保線程安全性,讀取-修改-寫入序列必須是原子的,將其稱為復(fù)合操作。復(fù)合操作包含了一組必須以原子方式執(zhí)行的接口以確保線程安全性。

      8、在無狀態(tài)的類中添加一個狀態(tài)時,如果這個狀態(tài)完全由線程安全的對象來管理,那么這個類仍然是線程安全的。(比如原子變量)

      9、如果多個狀態(tài)是相關(guān)的,需要同時被修改,那么對多個狀態(tài)的操作必須是串行的,需要進(jìn)行同步。要保持狀態(tài)的一致性,就需要在單個原子操作中更新所有相關(guān)的狀態(tài)變量。

      10、內(nèi)置鎖:synchronized(object){同步塊}

      Java的內(nèi)置鎖相當(dāng)于一種互斥體,這意味著最多只有一個線程能持有這種鎖,當(dāng)線程A嘗試獲取一個由線程B持有的鎖時,線程A必須等待或阻塞,直到線程B釋放這個鎖。如果B永遠(yuǎn)不釋放鎖,那么A也將永遠(yuǎn)地等待下去。

      11、重入:當(dāng)某個線程請求一個由其他線程持有的鎖時,發(fā)出請求的線程就會阻塞。然而,由于內(nèi)置鎖是可重入的,因此如果某個線程試圖獲得一個已經(jīng)由它自己持有的鎖,那么這個請求就會成功。重入意味著獲取鎖的操作的粒度是線程,而不是調(diào)用。重入的一種實現(xiàn)方法是,為每個鎖關(guān)聯(lián)一個獲取計數(shù)值和一個所有者線程。當(dāng)計數(shù)值為0時,這個鎖就被認(rèn)為是沒有被任何線程持有。當(dāng)線程請求一個未被持有的鎖時,JVM將記下鎖的持有者,并且將獲取計數(shù)值置1。如果一個線程再次獲取這個鎖,計數(shù)值將遞增,而當(dāng)線程退出同步代碼塊時,計數(shù)值會相應(yīng)遞減。當(dāng)計數(shù)值為0時,這個鎖將被釋放。

      12、對于可能被多個線程同時訪問的可變狀態(tài)變量,在訪問它時都需要持有同一個鎖,在這種情況下,我們稱狀態(tài)變量是由這個鎖保護(hù)的。

      每個共享的和可變的變量都應(yīng)該只由一個鎖來保護(hù),從而使維護(hù)人員知道是哪一個鎖。

      一種常見的加鎖約定是,將所有的可變狀態(tài)都封裝在對象內(nèi)部,并提供對象的內(nèi)置鎖(this)對所有訪問可變狀態(tài)的代碼路徑進(jìn)行同步。在這種情況下,對象狀態(tài)中的所有變量都由對象的內(nèi)置鎖保護(hù)起來。

      13、不良并發(fā):要保證同步代碼塊不能過小,并且不要將本應(yīng)是原子的操作拆分到多個同步代碼塊中。應(yīng)該盡量將不影響共享狀態(tài)且執(zhí)行時間較長的操作從同步代碼塊中分離出去,從而在這些操作的執(zhí)行過程中,其他線程可以訪問共享狀態(tài)。

      14、可見性:為了確保多個線程之間對內(nèi)存寫入操作的可見性,必須使用同步機(jī)制。

      15、加鎖與可見性:當(dāng)線程B執(zhí)行由鎖保護(hù)的同步代碼塊時,可以看到線程A之前在同一個同步代碼塊中的所有操作結(jié)果。如果沒有同步,那么就無法實現(xiàn)上述保證。加鎖的含義不僅僅局限于互斥行為,還包括內(nèi)存可見性。為了確保所有線程都能看到共享變量的最新值,所有執(zhí)行讀操作或?qū)懖僮鞯木€程都必須在同一個鎖上同步。

      16、volatile變量:當(dāng)把變量聲明為volatile類型后,編譯器與運行時都會注意到這個變量是共享的,因此不會將該變量上的操作與其他內(nèi)存操作一起重排序。volatile變量不會被緩存在寄存器或其他對處理器不可見的地方,因此在讀取volatile類型的變量時總會返回最新寫入的值。volatile的語義不足以確保遞增操作的原子性,除非你能確保只有一個線程對變量執(zhí)行寫操作。原子變量提供了“讀-改-寫”的原子操作,并且常常用做一種更好的volatile變量。

      17、加鎖機(jī)制既可以確保可見性,又可以確保原子性,而volatile變量只能確保可見性。

      18、當(dāng)且僅當(dāng)滿足以下的所有條件時,才應(yīng)該使用volatile變量:

      1)對變量的寫入操作不依賴變量的當(dāng)前值(不存在讀取-判斷-寫入序列),或者你能確保只有單個線程更新變量的值。

      2)該變量不會與其他狀態(tài)變量一起納入不可變條件中

      3)在訪問變量時不需要加鎖

      19、棧封閉:在棧封閉中,只能通過局部變量才能訪問對象。維護(hù)線程封閉性的一種更規(guī)范的方法是使用ThreadLocal,這個類能使線程的某個值與保存值的對象關(guān)聯(lián)起來,ThreadLocal通過了get和set等訪問接口或方法,這些方法為每個使用該變量的線程都存有一份獨立的副本,因此get總是返回由當(dāng)前執(zhí)行線程在調(diào)用set時設(shè)置的最新值。

      20、在并發(fā)程序中使用和共享對象時,可以使用一些使用的策略,包括:

      1)線程封閉:線程封閉的對象只能由一個線程擁有,對象被封閉在該線程中,并且只能由這個線程修改。

      2)只讀共享:在沒有額外同步的情況下,共享的只讀對象可以由多個線程并發(fā)訪問,但任何線程都不能修改它。共享的只讀對象包括不可變對象和事實不可變對象(從技術(shù)上來說是可變的,但其狀態(tài)在發(fā)布之后不會再改變)。

      3)線程安全共享。線程安全的對象在其內(nèi)部實現(xiàn)同步,因此多個線程可以通過對象的公有接口來進(jìn)行訪問而不需要進(jìn)一步的同步。

      4)保護(hù)對象。被保護(hù)的對象只能通過持有對象的鎖來訪問。保護(hù)對象包括封裝在其他線程安全對象中的對象,以及已發(fā)布并且由某個特定鎖保護(hù)的對象。

      21、饑餓:當(dāng)線程由于無法訪問它所需要的資源而不能繼續(xù)執(zhí)行時,就發(fā)生了饑餓(某線程永遠(yuǎn)等待)。引發(fā)饑餓的最常見資源就是CPU時鐘周期。比如線程的優(yōu)先級問題。在Thread API中定義的線程優(yōu)先級只是作為線程調(diào)度的參考。在Thread API中定義了10個優(yōu)先級,JVM根據(jù)需要將它們映射到操作系統(tǒng)的調(diào)度優(yōu)先級。這種映射是與特定平臺相關(guān)的,因此在某個操作系統(tǒng)中兩個不同的Java優(yōu)先級可能被映射到同一優(yōu)先級,而在另一個操作系統(tǒng)中則可能被映射到另一個不同的優(yōu)先級。

      當(dāng)提高某個線程的優(yōu)先級時,可能不會起到任何作用,或者也可能使得某個線程的調(diào)度優(yōu)先級高于其他線程,從而導(dǎo)致饑餓。

      通常,我們盡量不要改變線程的優(yōu)先級,只要改變了線程的優(yōu)先級,程序的行為就將與平臺相關(guān),并且會導(dǎo)致發(fā)生饑餓問題的風(fēng)險。

      事務(wù)T1封鎖了數(shù)據(jù)R,事務(wù)T2又請求封鎖R,于是T2等待。T3也請求封鎖R,當(dāng)T1釋放了R上的封鎖后,系統(tǒng)首先批準(zhǔn)了T3的請求,T2仍然等待。然后T4又請求封鎖R,當(dāng)T3釋放了R上的封鎖之后,系統(tǒng)又批準(zhǔn)了T的請求......T2可能永遠(yuǎn)等待

      22、活鎖

      活鎖是另一種形式的活躍性問題,該問題盡管不會阻塞線程,但也不能繼續(xù)執(zhí)行,因為線程將不斷重復(fù)執(zhí)行相同的操作,而且總會失敗。活鎖通常發(fā)生在處理事務(wù)消息的應(yīng)用程序中。如果不能成功處理某個消息,那么消息處理機(jī)制將回滾整個事務(wù),并將它重新放到隊列的開頭。雖然處理消息的線程并沒有阻塞,但也無法繼續(xù)執(zhí)行下去。這種形式的活鎖通常是由過度的錯誤恢復(fù)代碼造成的,因為它錯誤地將不可修復(fù)的錯誤作為可修復(fù)的錯誤。

      當(dāng)多個相互協(xié)作的線程都對彼此進(jìn)行響從而修改各自的狀態(tài),并使得任何一個線程都無法繼續(xù)執(zhí)行時,就發(fā)生了活鎖。要解決這種活鎖問題,需要在重試機(jī)制中引入隨機(jī)性。在并發(fā)應(yīng)用程序中,通過等待隨機(jī)長度的時間和回退可以有效地避免活鎖的發(fā)生。

      23、當(dāng)在鎖上發(fā)生競爭時,競爭失敗的線程肯定會阻塞。JVM在實現(xiàn)阻塞行為時,可以采用自旋等待(Spin-Waiting,指通過循環(huán)不斷地嘗試獲取鎖,直到成功),或者通過操作系統(tǒng)掛起被阻塞的線程。這兩種方式的效率高低,取決于上下文切換的開銷以及在成功獲取鎖之前需要等待的時間。如果等待時間較短,則適合采用自旋等待的方式,而如果等待時間較長,則適合采用線程掛起方式。

      24、有兩個因素將影響在鎖上發(fā)生競爭的可能性:鎖的請求頻率,以及每次持有該鎖的時間。如果二者的乘積很小,那么大多數(shù)獲取鎖的操作都不會發(fā)生競爭,會因此在該鎖上的競爭不會對可伸縮性造成嚴(yán)重影響。然而,如果在鎖上的請求量很高,那么需要獲取該鎖的線程將被阻塞并等待。在極端情況下,即使仍有大量工作等待完成,處理器也會被閑置。

      有3種方式可以降低鎖的競爭程度:

      1)減少鎖的持有時間:

      ①縮小鎖的范圍,將與鎖無關(guān)的代碼移出同步代碼塊,尤其是開銷較大的操作以及可能被阻塞的操作(IO操作)。

      當(dāng)把一個同步代碼塊分解為多個同步代碼塊時,反而會對性能提升產(chǎn)生負(fù)面影響。在分解同步代碼塊時,理想的平衡點將與平臺相關(guān),但在實際情況中,僅可以將一些大量的計算或阻塞操作從同步代碼塊移出時,才應(yīng)該考慮同步代碼塊的大小。

      ②減小鎖的粒度:鎖分解和鎖分段

      鎖分解是采用多個相互獨立的鎖來保護(hù)獨立的狀態(tài)變量,從而改變這些變量在之前由單個鎖來保護(hù)的情況。這些技術(shù)能減小鎖操作的粒度,并能實現(xiàn)更高的可伸縮性,然而,使用的鎖越多,那么發(fā)生死鎖的風(fēng)險也就越高。

      鎖分段:比如JDK1.7及之前的ConcurrentHashMap采用的方式就是分段鎖的方式。

      2)降低鎖的請求頻率

      3)使用帶有協(xié)調(diào)機(jī)制的獨占鎖,這些機(jī)制允許更高的并發(fā)性

      總結(jié)了線程安全性的二十四個精華問題

      比如讀寫鎖,并發(fā)容器等

      任務(wù)調(diào)度

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:excel函數(shù)怎樣組合兩個單元格
      下一篇:好用的協(xié)同OKR軟件(OKR的應(yīng)用)
      相關(guān)文章
      亚洲av日韩av欧v在线天堂| 国产精品亚洲片夜色在线| 亚洲GV天堂GV无码男同| 亚洲youjizz| 久久精品国产亚洲AV蜜臀色欲| 亚洲黄色三级网站| 亚洲黄色在线网站| 亚洲婷婷在线视频| 亚洲五月综合网色九月色| 国产成人精品日本亚洲专| 亚洲三级高清免费| 亚洲日本久久久午夜精品 | 亚洲看片无码在线视频| 亚洲激情视频图片| 亚洲影院天堂中文av色| 亚洲高清乱码午夜电影网| 国产精品无码亚洲一区二区三区| 麻豆亚洲AV成人无码久久精品 | 亚洲高清中文字幕综合网| 亚洲精品美女在线观看播放| 亚洲AV无码精品无码麻豆| 亚洲第一中文字幕| 亚洲女同成人AⅤ人片在线观看| 亚洲精品天堂在线观看| 亚洲欧美日韩中文字幕一区二区三区 | 亚洲AV无码专区亚洲AV伊甸园| 亚洲AV日韩AV永久无码久久| 久久99亚洲网美利坚合众国| 亚洲国产成人久久99精品| 亚洲色欲啪啪久久WWW综合网| 亚洲AV香蕉一区区二区三区| 亚洲VA综合VA国产产VA中| 亚洲中文字幕无码爆乳AV| 亚洲欧洲一区二区| 亚洲一卡2卡4卡5卡6卡残暴在线| 美女视频黄免费亚洲| 怡红院亚洲红怡院在线观看| 久久久久亚洲av毛片大| 亚洲AV无码国产精品色午友在线 | 亚洲A丁香五香天堂网| 日本亚洲视频在线 |