1. 程式人生 > >深入理解Java鎖---概念篇

深入理解Java鎖---概念篇

Java鎖

什麼是鎖

多執行緒訪問同一資源,對資源進行了非原子性操作,產生的併發安全問題。為了解決這種併發安全問題產生了鎖

那麼什麼是併發安全問題?

參照資料庫隔離級別來說簡單一點

1、髒讀:事務A讀取了事務B更新的資料,然後B回滾操作,那麼A讀取到的資料是髒資料

2、不可重複讀:事務 A 多次讀取同一資料,事務 B 在事務A多次讀取的過程中,對資料作了更新並提交,導致事務A多次讀取同一資料時,結果 不一致。

3、幻讀:系統管理員A將資料庫中所有學生的成績從具體分數改為ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。

事務隔離級別 髒讀 不可重複讀 幻讀
讀未提交(read-uncommitted)
不可重複讀(read-committed)
可重複讀(repeatable-read)
序列化(serializable)

簡單概括一下,就是指對資源的非原子性操作,會產生 髒讀,幻讀,不可重讀的情況。

好,知道了什麼是併發安全問題,那麼就產生了鎖來解決這種問題。那麼鎖分哪些呢?有什麼區別呢?

鎖分類(二類)

鎖從巨集觀上分類,分為悲觀鎖與樂觀鎖。

  1. 樂觀鎖
    樂觀鎖是一種樂觀思想,即認為讀多寫少,遇到併發寫的可能性低,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,採取在寫時先讀出當前版本號,然後加鎖操作(比較跟上一次的版本號,如果一樣則更新),如果失敗則要重複讀-比較-寫的操作。
    java中的樂觀鎖基本都是通過CAS操作實現的,CAS是一種更新的原子操作,比較當前值跟傳入值是否一樣,一樣則更新,否則失敗。

  2. 悲觀鎖
    悲觀鎖是就是悲觀思想,即認為寫多,遇到併發寫的可能性高,每次去拿資料的時候都認為別人會修改,所以每次在讀寫資料的時候都會上鎖,這樣別人想讀寫這個資料就會block直到拿到鎖。java中的悲觀鎖就是Synchronized,AQS框架下的鎖則是先嚐試cas樂觀鎖去獲取鎖,獲取不到,才會轉換為悲觀鎖,如RetreenLock。

鎖分類–功能區分

  • 可重入鎖
  • 不可重入鎖
  • 公平鎖
  • 非公平鎖
  • 自旋鎖

我們之前說了,為什麼會有鎖,因為有併發安全問題,那麼為什麼有這麼多種鎖呢,那是因為併發安全問題又細分了好多,現在一一解釋一下,為什麼會產生上面的那些鎖

可重入

什麼是可重入? 簡單說就是同一執行緒在持有鎖的情況下,可以不釋放鎖連續訪問該鎖物件的其他同步方法,直白些就是,一個物件有N個方法,執行緒訪問了A方法,獲取到了鎖,同時A方法呼叫了 物件的B方法,那麼該執行緒就可以在不釋放鎖(意味著不需要再次競爭鎖)的情況下訪問B方法
公平鎖
什麼是公平? 就是按照先到先得的思路,比如排隊打飯,誰先來就先給誰打飯,而不是大家一窩蜂搶,誰搶到就給誰打飯,那麼那些瘦弱的小朋友豈不是要餓死,所以引入了公平的概念,執行緒也是這樣。大家知道執行緒靠競爭獲取CPU執行片段,從而獲取鎖。那麼會不會出現極端情況,有個執行緒一直都競爭不到,那麼那個執行緒豈不是廢了。所以這裡引入了公平鎖的概念

自旋鎖

什麼是自旋? 為什麼要自旋? 因為JVM 認為在多數情況下,鎖一般是隻由一個執行緒在使用,那麼執行緒使用完畢之後釋放掉,下次還是這個執行緒又來了,還要在重新獲取鎖,是個問題,那麼怎麼辦呢? 就是執行緒在獲取鎖,執行完畢之後,不釋放鎖,一直佔有,等到有人要獲取鎖了它才釋放,如果這個人還是他自己,那麼他就無需再次競爭鎖了,直接就進來執行了,這個概念是個優化概念,並不是問題、

好了,以上有個大概的認知,Java 中提供了以上所有的解決思路和類庫。