java线程同步——条件对象+synchronized 关键字
【0】README
0.1) 本文描述轉(zhuǎn)自 core java volume 1, 源代碼為原創(chuàng),旨在理解 java線程同步——條件對象+synchronized 關(guān)鍵字 的相關(guān)知識;
0.2)for full source code : https://github.com/pacosonTang/core-java-volume/blob/master/chapter14/SynchBank.java
【1】條件對象
1.1)為什么引入條件對象:通常,線程進(jìn)入臨界區(qū), 卻發(fā)現(xiàn)在某一條件滿足后它才能執(zhí)行, 要使用一個條件對象來管理那些已經(jīng)獲得了一個鎖但是卻不能做有用工作的線程;
1.2)看個荔枝:
- 1.2.1)我們避免選擇沒有足夠資金的賬戶作為轉(zhuǎn)出賬戶:
- 1.2.2)當(dāng)前線程有可能在 調(diào)用 transfer之前就被CPU切斷了
- 1.2.3)我們必須要確保: 沒有其他線程在本檢查余額 與轉(zhuǎn)賬活動間修改余額。通過使用鎖保護(hù)來支持這一點:
1.3)一個鎖對象可以有一個或多個條件對象。 你可以使用 newCondition 方法獲得一個條件對象;
- 1.3.1)如果transfer 發(fā)現(xiàn)余額不足,它可以調(diào)用:
1.4)等待獲得鎖的線程和調(diào)用 await 方法的線程存在本質(zhì)的不同:
- 1.4.1)一旦一個線程調(diào)用 await 方法, 它進(jìn)入該條件的等待集, 當(dāng)鎖可用時,該線程不能馬上解除阻塞;
- 1.4.2)相反,它處于阻塞狀態(tài), 直到另一個線程調(diào)用同一個條件上的signalAll 方法為止, 這一調(diào)用重新激活 因為這一條件而等待的所有線程;
- 1.4.3)一旦鎖成為可用的, 它們中的某個將從 await 方法調(diào)用返回, 獲得該鎖并從阻塞的地方繼續(xù)執(zhí)行;
1.5)容易造成死鎖:(干貨)
- 1.5.1)原因: 當(dāng)一個線程調(diào)用 await 方法時, 它沒有辦法重新激活自身。 它寄希望于其他線程,然而,如果最后一個活動線程在解除其他線程的阻塞狀態(tài)之前就調(diào)用了 await 方法, 那么它就 被阻塞了, 這將導(dǎo)致所有的線程都處于阻塞狀態(tài),導(dǎo)致死鎖;
- 1.5.2)解決方法:應(yīng)該何時調(diào)用 signalAll 方法呢?經(jīng)驗上講, 在對象的狀態(tài)有利于等待線程的方法改變時調(diào)用 signalAll方法;
Attention)
- A1)注意, 調(diào)用 signalAll 不會立即激活一個等待線程, 它僅僅解除等待線程的阻塞,以便這些線程可以在當(dāng)前線程退出同步方法后, 通過競爭實現(xiàn)對對象的訪問;(干貨——signalAll方法的作用)
- A2)另一個方法 signal: 則是隨機解除等待集中某個線程的阻塞狀態(tài),這比解除所有線程的阻塞更加有效, 但也存在危險;(干貨——signal 方法的作用)
Warning)
- W1)當(dāng)一個線程擁有某個條件的鎖時,它僅僅可以在該條件上調(diào)用 await, signalAll 或 signal 方法;
- W2)即是, 一個系統(tǒng)中有多個條件變量(Condition), 每個條件上等待的線程不同, 某條件下的線程只喚醒該條件下的等待進(jìn)程;
【2】synchronized 關(guān)鍵字
2.1)總結(jié)一下有關(guān)鎖和條件的關(guān)鍵之處:
- 2.1.1)鎖用來保護(hù)代碼片段, 任何時刻只能有一個線程執(zhí)行被保護(hù)的代碼;
- 2.1.2)鎖可以管理試圖進(jìn)入被保護(hù)代碼段的線程;
- 2.1.3)鎖可以擁有一個或多個相關(guān)的條件對象;
- 2.1.4)每個條件對象管理那些已經(jīng)進(jìn)入被保護(hù)的代碼段但還不能運行的線程;
2.2) Lock 和 Condition 接口專門為 程序設(shè)計人員提供了 高度的鎖定控制;
2.3)synchronized 關(guān)鍵字: 可用于定義 同步方法和 同步塊以保護(hù)這個方法或同步塊中的代碼 在同一時間只能被一個線程訪問;
2.4)wait 方法添加一個線程到等待集中, notifyAll/notify 方法解除等待線程的阻塞狀態(tài);
- 2.4.1)換句話說: 調(diào)用wait 和 notifyAll 方法 等價于 condition.await() 和 condition.signalAll() 方法;
Annotation)
- A1) wait, notifyAll , notify 方法是 Object的final方法;
- A2) await, signalAll, signal 方法 是Condition 接口的方法, 以便與上述方法不會發(fā)生沖突;
2.5) 內(nèi)部鎖和條件存在一些局限:
- 2.5.1)不能中斷一個正在試圖獲得鎖的過程;
- 2.5.2)試圖獲得鎖時不能設(shè)定超時;
- 2.5.3)每個鎖僅有單一條件,可能是不夠的;
2.6)在代碼中應(yīng)該使用哪一種? Lock 和 Condition 對象還是同步方法?下面是建議:
- 2.6.1)最好既不用 Lock/Condition 也不用 synchronized關(guān)鍵字; 在許多case 下,你可以使用 java.util.concurrent 包中的一種機制, 它會為你處理所有的加鎖。 你會看到如何使用阻塞隊列來不同完成一個共同任務(wù)的線程; (干貨——阻塞隊列的作用)
- 2.6.2)如果 synchronized關(guān)鍵字適合, 請盡量使用它;
- 2.6.3)如果特別需要 Lock/Condition 結(jié)構(gòu)提供的獨有特性, 才使用 Lock/Condition;
總結(jié)
以上是生活随笔為你收集整理的java线程同步——条件对象+synchronized 关键字的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vivo X100 Pro 机型入网,消
- 下一篇: 体检前不能喝水?这项“体检须知”不但无用