本文翻譯和原創各佔一半,因此仍是厚顏無恥歸類到原創好了...
https://howtodoinjava.com/jav...
java 5 其中一個使人振奮的改進是新增了支持原子操做的類型,例如 AtomicInteger
, AtomicLong
等。在多線程環境中進行簡單的自增自減操做時,這些原子類能幫助你減小不少用於多線程同步的複雜代碼。這些原子類依賴於 CAS (compare and swap) 算法,接下來咱們會討論 CAS 這個概念。java
傳統的鎖機制,例如 java 的 synchronized
關鍵字,他表明了 java 中悲觀鎖技術,保證了某一時刻僅有一個線程能訪問同步代碼/方法。synchronized
可以很好地工做,卻有着 (相對) 比較大的性能開銷。
樂觀鎖 (相對悲觀鎖) 對性能會有很大的幫助。他的核心思想是:你寄但願於在沒有衝突的狀況下完成一次更新操做,使用樂觀鎖技術更新時會進行 「衝突檢測」 來判斷是否有其餘的線程干擾,如果 (有其餘線程干擾) 則視本次更新操做失敗,通常會進行重試 (能夠了解一下CAS自旋)。Compare and Swap
就是典型的樂觀鎖技術。算法
CAS 算法會先對一個內存變量(位置) V 和一個給定的值進行比較 A ,若是相等,則用一個新值 B 去修改這個內存變量(位置)。上述過程會做爲一個原子操做完成 (intel處理器經過 cmpxchg
指令系列實現)。CAS 原子性保證了新值的計算是基於上一個有效值,期間若是內存變量(位置) V 被其餘線程更新了,本線程的 CAS 更新操做將會失敗。CAS 操做必須告訴調用者成功與否,能夠返回一個 boolean 值來表示,或者返回一個從內存變量讀到的值 (應該是上一次有效值)多線程
CAS 操做數有三個:性能
CAS 表示:「我認爲如今 V 的值仍是以前我讀到的舊值 A,如果則用新值 B 覆蓋內存變量 V,不然不作任何動做並告訴調用者操做失敗」。CAS 是一項樂觀鎖技術,他在更新的時候老是但願能成功 (沒有衝突),但也能檢測出來自其餘線程的衝突和干擾
這裏咱們關注一下ReentrantLock
鎖定和解鎖那部分的源碼ui
//ReentrantLock.lock() public void lock() { sync.lock(); }
他依賴了其內部類Sync
的 lock()
,如下是內部類 Sync
(繼承了隊列同步器 AQS)線程
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; abstract void lock(); ................
Sync
仍是個抽象類,通常 new ReentrantLock()
時建立的是 NonfairSync
翻譯
// ReentrantLock的構造方法 public ReentrantLock() { sync = new NonfairSync(); }
下面就是NonfairSync
的 lock()
方法了code
final void lock() { if (compareAndSetState(0, 1)) // 1 setExclusiveOwnerThread(Thread.currentThread()); // 2 else acquire(1); // 3 }
compareAndSetState()
承繼自隊列同步器 AQS,封裝了 CAS 指令。由於是 NonfairSync
非公平鎖,因此一上來就嘗試搶佔鎖:給定舊值 0 並但願用新值 1 去更新內存變量 State。若更新成功則視爲獲取鎖成功,並執行 2鎖用完了要釋放,下面貼出 unlock()
方法繼承
// ReentrantLock.unlock() public void unlock() { sync.release(1); }
這裏仍是依賴了 sync,release()
是 AQS 的通用方法,其內部調用了 tryRelease()
(由 Sync 類實現),這裏直接貼出 Sync 的 tryRelease()
隊列
protected final boolean tryRelease(int releases) { // releases 參數的值是上面傳進來的 1 int c = getState() - releases; // 1 if (Thread.currentThread() != getExclusiveOwnerThread()) // 1.5 throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { // 2 free = true; setExclusiveOwnerThread(null); } setState(c); // 3 return free; }
ReentrantLock
是可重入鎖 (當前線程可屢次獲取鎖),因此 State 的值是能夠大於 1 的。AQS 隊列同步器以及 java.util.concurrent
下各類鎖和原子類都運用到的 CAS 算法,有時間的同窗建議閱讀加深印象。