synchronized及JUC顯式locks?使用原理解析
一、synchronized 有不足
新事物的出現(xiàn)要不是替代老事物,要么就是對老事物的補充
JUC 的 locks 就是對 synchronized 的補充
- 從開始競爭鎖 到拿到鎖這段時間,調(diào)用線程一直是阻塞狀態(tài),啥都干不了
- 已經(jīng)占有的資源也釋放不了,別的線程也無法獲得;這種不可搶占的情況,更容易帶來死鎖(死鎖產(chǎn)生的原理就是:我占著你要用的資源不給你,你卻不能搶)
- 只有一個條件變量(條件等待隊列),用于線程間的協(xié)調(diào)、通信
二、改進意見
采用更多的措施以避免死鎖 :
讓不能搶占 變?yōu)?可搶占,占用部分資源的線程進一步申請其他資源時
- 如果能快速申請到,就申請
- 如果不能快速申請到,可以主動釋放它占有的資源
使用者自己可創(chuàng)建多個條件變量,用于線程間的協(xié)調(diào)、通信。
三、可搶占的方法論
3.1 能夠響應中斷
synchronized
的問題是:持有鎖 A 后,如果嘗試獲取鎖 B 失敗,那么線程就進入阻塞狀態(tài),一旦發(fā)生死鎖,就沒有任何機會來喚醒阻塞的線程。但如果阻塞狀態(tài)的線程能夠響應中斷信號,也就是說當我們給阻塞的線程發(fā)送中斷信號的時候,能夠喚醒它,那它就有機會釋放曾經(jīng)持有的鎖 A。這樣就破壞了不可搶占條件了。
3.2 支持超時
如果線程在一段時間之內(nèi)沒有獲取到鎖,不是進入阻塞狀態(tài),而是返回一個錯誤,那這個線程也有機會釋放曾經(jīng)持有的鎖。這樣也能破壞不可搶占條件。
3.3 非阻塞地獲取鎖
如果嘗試獲取鎖失敗,并不進入阻塞狀態(tài),而是直接返回,那這個線程也有機會釋放曾經(jīng)持有的鎖。這樣也能破壞不可搶占條件。
四、可搶占的實現(xiàn) - JUC 的 locks
// 支持中斷的API void lockInterruptibly() throws InterruptedException; // 支持超時的API boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 支持非阻塞獲取鎖的API boolean tryLock();
五、多個 Condition(條件變量或條件等待隊列)
等效于管程中的條件變量,條件變量用于線程間的同步。通過java.util.concurrent.locks.Lock#newCondition()
來創(chuàng)建,每個 Condition
都具有一個 waitSet
;這樣鎖對象就具備了多個waitSet
; Condition
提供了以下方法:用于線程的協(xié)作(線程等待/激活)。
//線程加入此條件變量的等待隊列;類似Object.wait();使用時也要放到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() //激活此條件變量中的一個線程;類似Object.notify() java.util.concurrent.locks.Condition#signal() //激活此條件變量中的所有線程;類似Object.notifyAll() java.util.concurrent.locks.Condition#signalAll()
java doc 示例:一個有界緩沖,兩個條件等待隊列,分別被生產(chǎn)者線程和消費者線程來使用。
- 生產(chǎn)者線程在 notFull 條件隊列中等待;意思為生產(chǎn)者線程要阻塞等待,直到 有界緩沖不是滿的,才能 put
- 消費者線程在 notEmpty 條件隊列中等待;意思為消費者線程要阻塞等待,直到有界緩沖不是空的,才能 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 使用原理解析的詳細內(nèi)容,更多關(guān)于synchronized JUC顯式locks 的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解IDEA 中使用Maven創(chuàng)建項目常見錯誤和使用技巧(推薦)
這篇文章主要介紹了詳解IDEA 中使用Maven創(chuàng)建項目常見錯誤和使用技巧(推薦),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07springboot?vue接口測試HutoolUtil?TreeUtil處理樹形結(jié)構(gòu)
這篇文章主要介紹了springboot?vue接口測試HutoolUtil?TreeUtil處理樹形結(jié)構(gòu),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05Springboot+Mybatis實現(xiàn)分頁加條件查詢功能
這篇文章主要為大家詳細介紹了Springboot+Mybatis實現(xiàn)分頁加條件查詢,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-04-04淺談java 增強型的for循環(huán) for each
下面小編就為大家?guī)硪黄獪\談java 增強型的for循環(huán) for each。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10解決在for循環(huán)中remove list報錯越界的問題
這篇文章主要介紹了解決在for循環(huán)中remove list報錯越界的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12