摘要:在Java中提供了synchronized關鍵字來保證只有一個線程能夠訪問同步代碼塊 。既然已經提供了synchronized關鍵字,那為何在Java的SDK包中,還會提供Lock接口呢?這是不是重復造輪子,多此一舉呢?本文分享自華為云社區《【高并發】Java中提供了synchronized,為什么還要提供Lock呢?》,作者: 冰 河 。
在Java中提供了synchronized關鍵字來保證只有一個線程能夠訪問同步代碼塊 。既然已經提供了synchronized關鍵字,那為何在Java的SDK包中,還會提供Lock接口呢?這是不是重復造輪子,多此一舉呢?今天,我們就一起來探討下這個問題 。
再造輪子?既然JVM中提供了synchronized關鍵字來保證只有一個線程能夠訪問同步代碼塊,為何還要提供Lock接口呢?這是在重復造輪子嗎?Java的設計者們為何要這樣做呢?讓我們一起帶著疑問往下看 。
為何提供Lock接口?很多小伙伴可能會聽說過,在Java 1.5版本中,synchronized的性能不如Lock,但在Java 1.6版本之后,synchronized做了很多優化,性能提升了不少 。那既然synchronized關鍵字的性能已經提升了,那為何還要使用Lock呢?
如果我們向更深層次思考的話,就不難想到了:我們使用synchronized加鎖是無法主動釋放鎖的,這就會涉及到死鎖的問題 。
死鎖問題如果要發生死鎖,則必須存在以下四個必要條件,四者缺一不可 。

文章插圖
- 互斥條件
- 不可剝奪條件
- 請求與保持條件
- 循環等待條件
synchronized的局限性如果我們的程序使用synchronized關鍵字發生了死鎖時,synchronized關鍵是是無法破壞“不可剝奪”這個死鎖的條件的 。這是因為synchronized申請資源的時候,如果申請不到,線程直接進入阻塞狀態了,而線程進入阻塞狀態,啥都干不了,也釋放不了線程已經占有的資源 。
然而,在大部分場景下,我們都是希望“不可剝奪”這個條件能夠被破壞 。也就是說對于“不可剝奪”這個條件,占用部分資源的線程進一步申請其他資源時,如果申請不到,可以主動釋放它占有的資源,這樣不可剝奪這個條件就破壞掉了 。
如果我們自己重新設計鎖來解決synchronized的問題,我們該如何設計呢?
解決問題了解了synchronized的局限性之后,如果是讓我們自己實現一把同步鎖,我們該如何設計呢?也就是說,我們在設計鎖的時候,要如何解決synchronized的局限性問題呢?這里,我覺得可以從三個方面來思考這個問題 。

文章插圖
【Java:既然有了synchronized,為什么還要提供Lock?】(1)能夠響應中斷 。synchronized的問題是,持有鎖A后,如果嘗試獲取鎖B失敗,那么線程就進入阻塞狀態,一旦發生死鎖,就沒有任何機會來喚醒阻塞的線程 。但如果阻塞狀態的線程能夠響應中斷信號,也就是說當我們給阻塞的線程發送中斷信號的時候,能夠喚醒它,那它就有機會釋放曾經持有的鎖A 。這樣就破壞了不可剝奪條件了 。
經驗總結擴展閱讀
- 附:2種實現方式詳細對比 Java 動態代理原理圖解
- 深度剖析Java的volatile實現原理,再也不怕面試官問了
- 6 Java多線程:鎖與AQS(下)
- 三十九 Java開發學習----SpringBoot整合mybatis
- JavaSPI詳解
- 2023年1月搬家最佳吉日及入門時間
- day04-JavaScript01
- Java安全之Tomcat6 Filter內存馬
- 前女友有了新男朋友還能挽回嗎
- 帥農鳥哥是什么梗
