ReentrantLock 源码分析
ReentrantLock簡單使用demo如下:
Lock lock = new ReentrantLock(); lock.lock(); try {//業務邏輯 } finally {lock.unlock(); }注:獲取的鎖代碼要放到try塊之外,防止獲得鎖代碼異常,拋出異常的同時,也會導致一次鎖的釋放。釋放代碼一定要放到finally塊中。
AQS
了解java中的鎖,首先的了解AQS。
AQS(AbstractQueuedSynchronizer)隊列同步器。是用來構建鎖或者其它同步組件的基礎框架,他實現了一個int成員變量標識同步狀態(更改這個變量值來獲取和釋放鎖),通過內置的FIFO雙向隊列來完成資源獲取線程排隊的工作。
AQS可以實現獨占鎖和共享鎖,RenntrantLock實現的是獨占鎖,ReentrantReadWriteLock實現的是獨占鎖和共享鎖,CountDownLatch實現的是共享鎖。
ReentrantLock 類結構信息如下圖:
- ReentrantLock 實現 Lock 和 Serializable 接口
- RentrantLock 有三個內部類 Sync、NonfairSync 和 FairSync 類
- Sync 繼承 AbstractQueuedSynchronizer 抽象類
- NonfairSync(非公平鎖) 繼承 Sync 抽象類
- FairSync(公平鎖) 繼承 Sync 抽象類
公平鎖和非公平鎖
ReentrantLock 有兩種實現方式,公平鎖和非公平鎖。
公平鎖:當前線程不立刻獲得鎖,而是先直進入等待隊列中隊尾進行排隊獲取鎖。
非公平鎖:當前線程首先嘗試獲取一下鎖(僅僅嘗試一下),如果獲取不到,則乖乖的進入到等待隊列中去排隊。
ReentrantLock實現公平鎖和非公平鎖代碼如下:
/*** Creates an instance of {@code ReentrantLock}.* This is equivalent to using {@code ReentrantLock(false)}.*/public ReentrantLock() {sync = new NonfairSync();}/*** Creates an instance of {@code ReentrantLock} with the* given fairness policy.** @param fair {@code true} if this lock should use a fair ordering policy*/public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}* 獲取非公平鎖 *
/*** Performs lock. Try immediate barge, backing up to normal* acquire on failure.*/final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}tryAcquire調用nonfairTryAcquire方法來第二次嘗試獲得鎖
1. 如果state變量為0,則進行CAS嘗試更新state來獲得鎖,并把該線程設置成獨占鎖,并返回true。
2. 如果state變量不為0,則判斷當前線程是否為獨占鎖,如果是,則當前state+1(可重入鎖),表示獲取鎖成功,更新state值,并返回true。這里更新state變量,不需要CAS更新,因為,當前線程已經獲得鎖。
將構造的同步節點加入到同步隊列中
1. 使用鏈表的方式把該Node節點添加到隊列尾部,如果tail的前驅節點不為空(隊列不為空),則進行CAS添加到隊列尾部。
2. 如果更新失敗(存在并發競爭更新),則進入enq方法進行添加
該方法使用CAS自旋的方式來保證向隊列中添加Node(同步節點簡寫Node)
1. 如果隊列為空,則把當前Node設置成頭節點
2. 如果隊列不為空,則向隊列尾部添加Node
在acquireQueued方法中,當前線程在死循環中嘗試獲取同步狀態,
1. 如果當前節點的前驅節點頭節點才能嘗試獲得鎖,如果獲得成功,則把當前線程設置成頭結點,把之前的頭結點從隊列中移除,等待垃圾回收(沒有對象引用)
2. 如果獲取鎖失敗則進入shouldParkAfterFailedAcquire方法中檢測當前節點是否可以被安全的掛起(阻塞),如果可以安全掛起則進入parkAndCheckInterrupt方法,把當前線程掛起,并檢查剛線程是否執行了interrupted方法。
waitStatus狀態值
| CANCELLED | 1 | 等待超時或者中斷,需要從同步隊列中取消 |
| SIGNAL | -1 | 后繼節點出于等待狀態,當前節點釋放鎖后將會喚醒后繼節點 |
| CONDITION | -2 | 節點在等待隊列中,節點線程等待在Condition上,其它線程對Condition調用signal()方法后,該節點將會從等待同步隊列中移到同步隊列中,然后等待獲取鎖。 |
| PROPAGATE | -3 | 表示下一次共享式同步狀態獲取將會無條件地傳播下去 |
| INITIAL | 0 | 初始狀態 |
把當前線程掛起,并檢查剛線程是否執行了interrupted方法,并返回true、false。
公平鎖
公平鎖和非公平鎖實現方式是一樣的,唯一不同的是tryAcquire方法的實現,下面是公平鎖tryAcquire方法實現:
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}如果不是頭結點或獲取鎖失敗則,則判斷當前線程是否為獨占鎖,如果是,則當前state+1(可重入鎖),表示獲取鎖成功,更新state值,并返回true。這里更新state變量,不需要CAS更新,因為,當前線程已經獲得鎖。
????本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8
????點擊這里快速進入簡書
總結
以上是生活随笔為你收集整理的ReentrantLock 源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HttpClient 学习整理
- 下一篇: HashMap 源码解析(JDK1.8)