Jdk1.6 JUC原始碼解析(7)-locks-ReentrantLock
轉自 大飛的部落格
http://brokendreams.iteye.com/blog/2250883
http://brokendreams.iteye.com/blog/2250883
Jdk1.6 JUC原始碼解析(7)-locks-ReentrantLock
作者:大飛
功能簡介:
- Java程式碼層面提供的鎖機制,可做為Synchronized(jvm內建)的替代物,和Synchronized一樣都是可重入的。
- 與Synchronized相比較而言,ReentrantLock有以下優勢:支援公平/非公平鎖、支援可中斷的鎖、支援非阻塞的tryLock(可超時)、支援鎖條件、可跨程式碼塊使用(一個地方加鎖,另一個地方解鎖),總之比Synchronized更加靈活。但也有缺點,比如鎖需要顯示解鎖、無法充分享用JVM內部效能提升帶來的好處等等。
原始碼分析:
- ReentrantLock實現了Lock介面,先來看下這個介面:
- public interface Lock {
- /**
- * 獲取鎖,如果鎖無法獲取,當前執行緒被阻塞,直到鎖可以獲取並獲取成功為止。
- */
- void lock();
- /**
- * 在當前執行緒沒有被中斷的情況下獲取鎖。
- *
- * 如果獲取成功,方法結束。
- *
- * 如果鎖無法獲取,當前執行緒被阻塞,直到下面情況發生:
- *
- * 1.當前執行緒(被喚醒後)成功獲取鎖。
- * 2.當前執行緒被其他執行緒中斷。
- */
- void lockInterruptibly() throws InterruptedException;
- /**
- * 如果當前鎖是可用的,獲取鎖。
- *
- * 獲取成功後,返回true。
- * 如果當前鎖不可用,返回false。
- */
- boolean tryLock();
- /**
- * 如果鎖在給定超時時間內可用,並且當前執行緒沒有被中斷,那麼獲取鎖。
- *
- * 如果鎖可用,獲取鎖成功並返回true。
- *
- * 如果鎖無法獲取,當前執行緒被阻塞,直到下面情況發生:
- *
- * 1.當前執行緒(被喚醒後)成功獲取鎖。
- * 2.當前執行緒被其他執行緒中斷。
- * 3.指定的等待時間超時。
- */
- boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
- /**
- * 釋放鎖。
- */
- void unlock();
- /**
- * 返回一個和當前鎖例項相關聯的條件。
- *
- * 當前執行緒必須首先獲取鎖後才能在鎖條件上等待。
- * 一個Condition的await()方法呼叫會在等待之前自動釋放鎖,在等待結束
- * 前重新獲取鎖。
- */
- Condition newCondition();
- }
- 之前分析AQS的時候提到過,基於AQS構建的同步機制都會使用內部幫助類繼承AQS的方式構建,看下ReentrantLock中的同步機制:
- //內部同步機制的引用。
- private final Sync sync;
- /**
- * 這個鎖實現的基本同步控制機制,下面會提供公平和非公平版本的子類。
- * 利用AQS的state來表示鎖持有(重入)的次數。.
- */
- static abstract class Sync extends AbstractQueuedSynchronizer {
- private static final long serialVersionUID = -5179523762034025860L;
- /**
- * Performs {@link Lock#lock}. The main reason for subclassing
- * is to allow fast path for nonfair version.
- */
- abstract void lock();
- /**
- * 方法用來支援非公平的tryLock
- */
- final boolean nonfairTryAcquire(int acquires) {
- final Thread current = Thread.currentThread();
- int c = getState();
- if (c == 0) {
- //如果當前沒有任何執行緒獲取鎖(鎖可用),嘗試設定state。
- if (compareAndSetState(0, acquires)) {
- //如果設定成功,將當前執行緒資訊設定到AQS中(所有權關聯)。
- setExclusiveOwnerThread(current);
- return true;
- }
- }
- //如果鎖已經被持有,那麼判斷一下持有鎖的執行緒是否為當前執行緒。
- else if (current == getExclusiveOwnerThread()) {
- //如果是當前執行緒在持有鎖,那麼這裡累計一下重入次數。
- int nextc = c + acquires;
- if (nextc < 0) // overflow 重入次數最大不能超過int的最大值
- throw new Error("Maximum lock count exceeded");
- //設定到AQS的state中
- setState(nextc);
- return true;
- }
- //如果鎖已經被持有,且持有執行緒不是當前執行緒,返回false。
- return false;
- }
- protected final boolean tryRelease(int releases) {
- //釋放時,這裡要減去重入次數。
- int c = getState() - releases;
- //判斷控制權關係是否正確。
- if (Thread.currentThread() != getExclusiveOwnerThread())
- throw new IllegalMonitorStateException();
- boolean free = false;
- if (c == 0) {
- //如果當前執行緒完全釋放了鎖(重入次數為0)
- free = true;
- //解除所有權關係。
- setExclusiveOwnerThread(null);
- }
- //設定重入次數。
- setState(c);
- //返回是否釋放成功(或者說是否完全釋放)。
- return free;
- }
- protected final boolean isHeldExclusively() {
- // While we must in general read state before owner,
- // we don't need to do so to check if current thread is owner
- return getExclusiveOwnerThread() == Thread.currentThread();
- }
- final ConditionObject newCondition() {
- return new ConditionObject();
- }
- // Methods relayed from outer class
- final Thread getOwner() {
- return getState() == 0 ? null : getExclusiveOwnerThread();
- }
- final int getHoldCount() {
- return isHeldExclusively() ? getState() : 0;
- }
- final boolean isLocked() {
- return getState() != 0;
- }
- /**
- * Reconstitutes this lock instance from a stream.
- * @param s the stream
- */
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
- setState(0); // reset to unlocked state
- }
- }
接下來先看一下非公平版本的子類:
- /**
- * Sync object for non-fair locks
- */
- final static class NonfairSync extends Sync {
- private static final long serialVersionUID = 7316153563782823691L;
- /**
- * Performs lock. Try immediate barge, backing up to normal
- * acquire on failure.
- */
- final void lock() {
- //這裡首先嚐試一個短程式碼路徑,直接CAS設定state,嘗試獲取鎖。
- //相當於一個插隊的動作(可能出現AQS等待佇列裡有執行緒在等待,但當前執行緒競爭成功)。
- if (compareAndSetState(0, 1))
- setExclusiveOwnerThread(Thread.currentThread());
- else
- acquire(1);//如果CAS失敗,呼叫AQS的獨佔請求方法。
- }
- protected final boolean tryAcquire(int acquires) {
- //呼叫上面父類的nonfairTryAcquire方法。
- return nonfairTryAcquire(acquires);
- }
- }
再來先看一下公平版本的子類:
- /**
- * Sync object for fair locks
- */
- final static class FairSync extends Sync {
- private static final long serialVersionUID = -3000897897090466540L;
- final void lock() {
- acquire(1);
- }
- /**
- * 公平版本的tryAcquire。
- * 只有在遞迴(重入)或者同步佇列中沒有其他執行緒
- * 或者當前執行緒是等待佇列中的第一個執行緒時才准許訪問。
- */
- protected final boolean tryAcquire(int acquires) {
- final Thread current = Thread.currentThread();
- int c = getState();
- if (c == 0) {
- if (!hasQueuedPredecessors() &&
- compareAndSetState(0, acquires)) { //如果當前鎖可用,且同步等待佇列中沒有其他執行緒,那麼嘗試設定state
- 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;
- }
- }
小總結一下:
非公平版的鎖-加鎖操作
1.當前執行緒首先會無條件的執行一個CAS操作來獲取鎖,如果CAS操作成功,獲取鎖成功。
2.如果第1步沒成功,當前會檢查鎖是否被其他執行緒持有,也就是鎖是否可用。
3.如果沒有其他執行緒持有鎖,會以CAS的方式嘗試獲取鎖,如果CAS操作成功,獲取鎖成功。
4.如果有其他執行緒持有鎖,會判斷一下持有鎖的執行緒是否為當前執行緒,如果是當前執行緒,重入次數+1,獲取鎖成功。
5.根據AQS的分析,上述2、3、4步會執行多次,如果最終獲取鎖失敗,當前執行緒會被阻塞,等待其他執行緒執行解鎖操作將其喚醒。
公平版的鎖-加鎖操作
1.當前執行緒首先會檢查鎖是否被其他執行緒持有,並且當前同步等待佇列裡有沒有其他執行緒在等待。
2.如果沒有其他執行緒持有鎖,且同步等待佇列裡沒有其他執行緒,會以CAS的方式嘗試獲取鎖,如果CAS操作成功,獲取鎖成功。
3.如果有其他執行緒持有鎖,會判斷一下持有鎖的執行緒是否為當前執行緒,如果是當前執行緒,重入次數+1,獲取鎖成功。
4.根據AQS的分析,上述1、2、3步會執行多次,如果最終獲取鎖失敗,當前執行緒會被阻塞,等待其他執行緒執行解鎖操作將其喚醒。
非公平版和公平版鎖的解鎖操作一樣
1.當前執行緒首先將鎖重入次數減1(AQS的state),如果減1後結果為0,將當前同步器的執行緒資訊置空,並喚醒同步等待佇列中隊頭的等待執行緒。
2.如果第1步中,重入次數減1後結果不為0(說明當前執行緒還持有當前鎖),方法結束。
- 有了內部的基礎同步機制,ReentrantLock的實現就很簡單了,直接看程式碼:
- /**
- * 預設情況下構建非公平鎖。
- */
- public ReentrantLock() {
- sync = new NonfairSync();
- }
- /**
- * 根據給定的公平策略生成相應的例項。
- *
- * @param fair {@code true} if this lock should use a fair ordering policy
- */
- public ReentrantLock(boolean fair) {
- sync = (fair)? new FairSync() : new NonfairSync();
- }
- public void lock() {
- sync.lock();
- }
- public void lockInterruptibly() throws InterruptedException {
- sync.acquireInterruptibly(1);
- }
- public boolean tryLock() {
- return sync.nonfairTryAcquire(1);
- }
- public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
- return sync.tryAcquireNanos(1, unit.toNanos(timeout));
- }
- public void unlock() {
- sync.release(1);
- }
- public Condition newCondition() {
- return sync.newCondition();
- }
最後看一下一些支援監測的方法:
- /**
- * 獲取當前執行緒的對當前鎖的持有(重入)次數。
- */
- public int getHoldCount() {
- return sync.getHoldCount();
- }
- /**
- * 判斷當前鎖是否被當前執行緒持有。
- */
- public boolean isHeldByCurrentThread() {
- return sync.isHeldExclusively();
- }
- /**
- * 判斷當前鎖是否被(某個執行緒)持有。
- */
- public boolean isLocked() {
- return sync.isLocked();
- }
- /**
- * 當前鎖是否為公平鎖。
- */
- public final boolean isFair() {
- return sync instanceof FairSync;
- }
- /**
- * 獲取持有當前鎖的執行緒。
- */
- protected Thread getOwner() {
- return sync.getOwner();
- }
- /**
- * 判斷是否有執行緒在當前鎖的同步等待佇列中等待。
- */
- public final boolean hasQueuedThreads() {
- return sync.hasQueuedThreads();
- }
- /**
- * 判斷給定的執行緒是否在當前鎖的同步等待佇列中等待。
- */
- public final boolean hasQueuedThread(Thread thread) {
- return sync.isQueued(thread);
- }
- /**
- * 獲取當前鎖的同步等待佇列中的等待執行緒(估計)數量。
- */
- public final int getQueueLength() {
- return sync.getQueueLength();
- }
- /**
- * 獲取當前鎖的同步等待佇列中等待的執行緒。
- */
- protected Collection getQueuedThreads() {
- return sync.getQueuedThreads();
- }
- /**
- * 判斷是否有執行緒在給定條件的條件等待佇列上等待。
- */
- public boolean hasWaiters(Condition condition) {
- if (condition == null)
- throw new NullPointerException();
- if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
- throw new IllegalArgumentException("not owner");
- return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
- }
- /**
- * 獲取給定條件的條件等待佇列中等待執行緒的(估計)數量。
- */
- public int getWaitQueueLength(Condition condition) {
- if (condition == null)
- throw new NullPointerException();
- if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
- throw new IllegalArgumentException("not owner");
- return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
- }
- /**
- * 獲取給定條件的條件等待佇列中等待執行緒。
- */
- protected Collection getWaitingThreads(Condition condition) {
- if (condition == null)
- throw new NullPointerException();
- if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
- throw new IllegalArgumentException("not owner");
- return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
- }
ReentrantLock的程式碼解析完畢!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-1835220/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JUC原始碼講解:逐步解析 join()原始碼
- JUC原始碼講解:逐步解析 Thread.init() 原始碼原始碼thread
- JUC原始碼學習筆記7——FutureTask原始碼解析,人生亦如是,run起來才有結果原始碼筆記
- JUC之CountDownLatch原始碼分析CountDownLatch原始碼
- JUC 原始碼講解:sleep()原始碼
- JUC之ReentrantLock原始碼分析ReentrantLock原始碼
- ConcurrentHashMap原始碼解析-Java7HashMap原始碼Java
- Java JUC CopyOnWriteArrayList 解析Java
- freeRTOS原始碼解析4--tasks.c 7原始碼
- Java JUC PriorityBlockingQueue解析JavaBloC
- Java JUC ReentrantLock解析JavaReentrantLock
- Java JUC ThreadPoolExecutor解析Javathread
- 學習JUC原始碼(2)——自定義同步元件原始碼元件
- 【JUC】JDK1.8原始碼分析之CyclicBarrier(四)JDK原始碼
- 【JUC】JDK1.8原始碼分析之CountDownLatch(五)JDK原始碼CountDownLatch
- 【JUC】JDK1.8原始碼分析之AbstractQueuedSynchronizer(二)JDK原始碼
- 【JUC】JDK1.8原始碼分析之Semaphore(六)JDK原始碼
- 【JUC】JDK1.8原始碼分析之LockSupport(一)JDK原始碼
- 《球球大作戰》原始碼解析(7):遊戲迴圈原始碼遊戲
- Java JUC ConcurrentLinkedQueue解析Java
- Java JUC LinkedBlockingQueue解析JavaBloC
- Java JUC ThreadLocalRandom類解析Javathreadrandom
- JUC之CountDownLatch的原始碼和使用場景分析CountDownLatch原始碼
- 【JUC】JDK1.8原始碼分析之ThreadPoolExecutor(一)JDK原始碼thread
- 【JUC】JDK1.8原始碼分析之ReentrantLock(三)JDK原始碼ReentrantLock
- 【JUC】JDK1.8原始碼分析之ConcurrentHashMap(一)JDK原始碼HashMap
- 【原始碼解析】- ArrayList原始碼解析,絕對詳細原始碼
- Java JUC ReentrantReadWriteLock解析Java
- Spark原始碼-SparkContext原始碼解析Spark原始碼Context
- JUC(4)---java執行緒池原理及原始碼分析Java執行緒原始碼
- JUC原始碼學習筆記6——ReentrantReadWriteLock原始碼筆記
- 【JUC】JDK1.8原始碼分析之LinkedBlockingQueue(四)JDK原始碼BloC
- CountDownLatch原始碼解析CountDownLatch原始碼
- LeakCanary原始碼解析原始碼
- vuex原始碼解析Vue原始碼
- ArrayBlockQueue原始碼解析BloC原始碼
- AsyncTask原始碼解析原始碼
- CopyOnWriteArrayList原始碼解析原始碼