標籤:原理 簡單 最大 aqs架構 就是 情況 exclusive 核心 cas
一、出現執行緒安全性問題的條件•在多線程的環境下•必須有共用資源•對共用資源進行非原子性操作
二、解決執行緒安全性問題的途徑•synchronized (偏向鎖,輕量級鎖,重量級鎖)•volatile•JDK提供的原子類•使用Lock(共用鎖定,排它鎖)
三、認識的“*鎖”
•偏向鎖Java偏向鎖(Biased Locking)是Java6引入的一項多線程最佳化。
偏向鎖,顧名思義,它會偏向於第一個訪問鎖的線程,如果在運行過程中,同步鎖只有一個線程訪問,不存在多線程爭用的情況,則線程是不需要觸發同步的,這種情況下,就會給線程加一個偏向鎖。
如果在運行過程中,遇到了其他線程搶佔鎖,則持有偏向鎖的線程會被掛起,JVM會消除它身上的偏向鎖,將鎖恢複到標準的輕量級鎖。
•輕量級鎖輕量級鎖是由偏向所升級來的,偏向鎖運行在一個線程進入同步塊的情況下,當第二個線程加入鎖爭用的時候,偏向鎖就會升級為輕量級鎖;•重量級鎖重量級鎖,就是讓爭搶鎖的線程從使用者態轉換成核心態。讓cpu藉助作業系統進行線程協調
•重入鎖重進入是指任意線程在擷取到鎖之後,再次擷取該鎖而不會被該鎖所阻塞。關聯一個線程持有人+計數器,重入意味著鎖操作的顆粒度為“線程
•自旋鎖
自旋鎖原理非常簡單,如果持有鎖的線程能在很短時間內釋放鎖資源,那麼那些等待競爭鎖的線程就不需要做核心態和使用者態之間的切換進入阻塞掛起狀態,它們只需要等一等(自旋),等持有鎖的線程釋放鎖後即可立即擷取鎖,這樣就避免使用者線程和核心的切換的消耗。
但是線程自旋是需要消耗cup的,說白了就是讓cup在做無用功,如果一直擷取不到鎖,那線程也不能一直佔用cup自旋做無用功,所以需要設定一個自旋等待的最大時間。
如果持有鎖的線程執行的時間超過自旋等待的最大時間扔沒有釋放鎖,就會導致其它爭用鎖的線程在最大等待時間內還是擷取不到鎖,這時爭用線程會停止自旋進入阻塞狀態。
•共用鎖定又稱讀鎖,若事務T對資料對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。
•獨佔鎖獨佔鎖定(Exclusive Locks,簡稱X鎖),又稱為寫鎖、獨佔鎖,是一種基本的鎖類型。
•獨佔鎖定獨佔鎖定(Exclusive Locks,簡稱X鎖),又稱為寫鎖、獨佔鎖,是一種基本的鎖類型。
•讀寫鎖讀寫鎖實際是一種特殊的自旋鎖,它把對共用資源的訪問者劃分成讀者和寫者,讀者只對共用資源進行讀訪問,寫者則需要對共用資源進行寫操作。
•公平鎖
公平和非公平鎖的隊列都基於鎖內部維護的一個雙向鏈表,表結點Node的值就是每一個請求當前鎖的線程。公平鎖則在於每次都是依次從隊首取值。
•非公平鎖
在等待鎖的過程中, 如果有任意新的線程妄圖擷取鎖,都是有很大的幾率直接擷取到鎖的。
•死結死結:兩個或多個線程相互等待對方釋放鎖,則會出現死結現象。java虛擬機器沒有檢測,也沒有採用措施來處理死結情況,所以多線程編程是應該採取措施避免死結的出現。一旦出現死結,整個程式即不會發生任何異常,也不會給出任何提示,只是所有線程都處於堵塞狀態。•
活鎖任務或者執行者沒有被阻塞,由於某些條件沒有滿足,導致一直重複嘗試,失敗,嘗試,失敗。活鎖和死結的區別在於,處於活鎖的實體是在不斷的改變狀態,所謂的“活”, 而處於死結的實體表現為等待;活鎖有可能自行解開,死結則不能。
•樂觀鎖
樂觀鎖是一種樂觀思想,即認為讀多寫少,遇到並發寫的可能性低,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,採取在寫時先讀出目前的版本號,然後加鎖操作(比較跟上一次的版本號碼,如果一樣則更新),如果失敗則要重複讀-比較-寫的操作。
java中的樂觀鎖基本都是通過CAS操作實現的,CAS是一種更新的原子操作,比較當前值跟傳入值是否一樣,一樣則更新,否則失敗。
•悲觀鎖悲觀鎖是就是悲觀思想,即認為寫多,遇到並發寫的可能性高,每次去拿資料的時候都認為別人會修改,所以每次在讀寫資料的時候都會上鎖,這樣別人想讀寫這個資料就會block直到拿到鎖。java中的悲觀鎖就是Synchronized,AQS架構下的鎖則是先嘗試cas樂觀鎖去擷取鎖,擷取不到,才會轉換為悲觀鎖,如RetreenLock。
Java並發編程原理與實戰二十:執行緒安全性問題簡單總結