synchronized及JUC顯式locks?使用原理解析
一、synchronized 有不足
新事物的出現(xiàn)要不是替代老事物,要么就是對(duì)老事物的補(bǔ)充
JUC 的 locks 就是對(duì) synchronized 的補(bǔ)充
- 從開(kāi)始競(jìng)爭(zhēng)鎖 到拿到鎖這段時(shí)間,調(diào)用線程一直是阻塞狀態(tài),啥都干不了
- 已經(jīng)占有的資源也釋放不了,別的線程也無(wú)法獲得;這種不可搶占的情況,更容易帶來(lái)死鎖(死鎖產(chǎn)生的原理就是:我占著你要用的資源不給你,你卻不能搶)
- 只有一個(gè)條件變量(條件等待隊(duì)列),用于線程間的協(xié)調(diào)、通信
二、改進(jìn)意見(jiàn)
采用更多的措施以避免死鎖 :
讓不能搶占 變?yōu)?可搶占,占用部分資源的線程進(jìn)一步申請(qǐng)其他資源時(shí)
- 如果能快速申請(qǐng)到,就申請(qǐng)
- 如果不能快速申請(qǐng)到,可以主動(dòng)釋放它占有的資源
使用者自己可創(chuàng)建多個(gè)條件變量,用于線程間的協(xié)調(diào)、通信。
三、可搶占的方法論
3.1 能夠響應(yīng)中斷
synchronized
的問(wèn)題是:持有鎖 A 后,如果嘗試獲取鎖 B 失敗,那么線程就進(jìn)入阻塞狀態(tài),一旦發(fā)生死鎖,就沒(méi)有任何機(jī)會(huì)來(lái)喚醒阻塞的線程。但如果阻塞狀態(tài)的線程能夠響應(yīng)中斷信號(hào),也就是說(shuō)當(dāng)我們給阻塞的線程發(fā)送中斷信號(hào)的時(shí)候,能夠喚醒它,那它就有機(jī)會(huì)釋放曾經(jīng)持有的鎖 A。這樣就破壞了不可搶占條件了。
3.2 支持超時(shí)
如果線程在一段時(shí)間之內(nèi)沒(méi)有獲取到鎖,不是進(jìn)入阻塞狀態(tài),而是返回一個(gè)錯(cuò)誤,那這個(gè)線程也有機(jī)會(huì)釋放曾經(jīng)持有的鎖。這樣也能破壞不可搶占條件。
3.3 非阻塞地獲取鎖
如果嘗試獲取鎖失敗,并不進(jìn)入阻塞狀態(tài),而是直接返回,那這個(gè)線程也有機(jī)會(huì)釋放曾經(jīng)持有的鎖。這樣也能破壞不可搶占條件。
四、可搶占的實(shí)現(xiàn) - JUC 的 locks
// 支持中斷的API void lockInterruptibly() throws InterruptedException; // 支持超時(shí)的API boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 支持非阻塞獲取鎖的API boolean tryLock();
五、多個(gè) Condition(條件變量或條件等待隊(duì)列)
等效于管程中的條件變量,條件變量用于線程間的同步。通過(guò)java.util.concurrent.locks.Lock#newCondition()
來(lái)創(chuàng)建,每個(gè) Condition
都具有一個(gè) waitSet
;這樣鎖對(duì)象就具備了多個(gè)waitSet
; Condition
提供了以下方法:用于線程的協(xié)作(線程等待/激活)。
//線程加入此條件變量的等待隊(duì)列;類似Object.wait();使用時(shí)也要放到while循環(huán)體內(nèi)。 java.util.concurrent.locks.Condition#await() java.util.concurrent.locks.Condition#awaitUninterruptibly() java.util.concurrent.locks.Condition#awaitNanos() java.util.concurrent.locks.Condition#await(long, java.util.concurrent.TimeUnit) java.util.concurrent.locks.Condition#awaitUntil() //激活此條件變量中的一個(gè)線程;類似Object.notify() java.util.concurrent.locks.Condition#signal() //激活此條件變量中的所有線程;類似Object.notifyAll() java.util.concurrent.locks.Condition#signalAll()
java doc 示例:一個(gè)有界緩沖,兩個(gè)條件等待隊(duì)列,分別被生產(chǎn)者線程和消費(fèi)者線程來(lái)使用。
- 生產(chǎn)者線程在 notFull 條件隊(duì)列中等待;意思為生產(chǎn)者線程要阻塞等待,直到 有界緩沖不是滿的,才能 put
- 消費(fèi)者線程在 notEmpty 條件隊(duì)列中等待;意思為消費(fèi)者線程要阻塞等待,直到有界緩沖不是空的,才能 take
class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
六、JUC中l(wèi)ocks的使用規(guī)范
6.1 保證鎖的釋放
Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
Lock lock = ...; if (lock.tryLock()) { try { // manipulate protected state } finally { lock.unlock(); } } else { // perform alternative actions }
6.2 循環(huán)體中使用 await()
while (XXX) condition.await();
6.3 同步代碼塊中使用 await()
必須先持有鎖
l.lock(); try { ... while (XXX) condition.await(); ... } finally { l.unlock(); }
以上就是synchronized及JUC顯式locks 使用原理解析的詳細(xì)內(nèi)容,更多關(guān)于synchronized JUC顯式locks 的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解IDEA 中使用Maven創(chuàng)建項(xiàng)目常見(jiàn)錯(cuò)誤和使用技巧(推薦)
這篇文章主要介紹了詳解IDEA 中使用Maven創(chuàng)建項(xiàng)目常見(jiàn)錯(cuò)誤和使用技巧(推薦),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07Idea創(chuàng)建Jsp項(xiàng)目完整版教程
一直在使用eclipse,對(duì)idea嗤之以鼻,前些日子換成了idea以后覺(jué)得太香了,這篇文章主要給大家介紹了關(guān)于Idea創(chuàng)建Jsp項(xiàng)目的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-04-04JVM 方法調(diào)用之動(dòng)態(tài)分派(詳解)
下面小編就為大家?guī)?lái)一篇JVM 方法調(diào)用之動(dòng)態(tài)分派(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05springboot?vue接口測(cè)試HutoolUtil?TreeUtil處理樹(shù)形結(jié)構(gòu)
這篇文章主要介紹了springboot?vue接口測(cè)試HutoolUtil?TreeUtil處理樹(shù)形結(jié)構(gòu),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05Springboot+Mybatis實(shí)現(xiàn)分頁(yè)加條件查詢功能
這篇文章主要為大家詳細(xì)介紹了Springboot+Mybatis實(shí)現(xiàn)分頁(yè)加條件查詢,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04淺談java 增強(qiáng)型的for循環(huán) for each
下面小編就為大家?guī)?lái)一篇淺談java 增強(qiáng)型的for循環(huán) for each。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問(wèn)題
這篇文章主要介紹了解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12Spring MVC實(shí)現(xiàn)的登錄攔截器代碼分享
這篇文章主要介紹了Spring MVC實(shí)現(xiàn)的登錄攔截器代碼分享,涉及攔截器的簡(jiǎn)單介紹,攔截器和過(guò)濾器的區(qū)以及攔截器實(shí)現(xiàn)代碼等相關(guān)內(nèi)容,這里分享給大家,供需要的朋友參考。2017-10-10