Java8 ReentrantLock(一) 源碼解析

 目錄

一、AbstractQueuedSynchronizer

1、定義

2、Unsafe objectFieldOffset和staticFieldOffset

3、Node

二、ReentrantLock

1、acquireQueued

2、lock

3、lockInterruptibly

4、tryLock

5、unlock

 6、其他方法實現總結


       ReentrantLock表示一個可重入的互斥鎖,跟synchronized語義基本一致,還擴展了部分功能。當某個線程調用lock方法返回後就表示該線程佔有了該鎖,如果再次調用lock方法就會立即返回,可通過isHeldByCurrentThread或者getHoldCount方法來判斷是否佔有該鎖。ReentrantLock默認是非公平鎖,即哪個線程獲取鎖是完全隨機的,長時間等待的線程不會優先獲取鎖,如果將構造方法的boolean參數fairness設置爲true,則變成了公平鎖,該參數默認爲false,公平鎖可保證長時間等待的線程優先獲取鎖,但是會導致併發情況下應用程序的吞吐量大幅降低,另外公平鎖不能保證系統進程調度的公平,有可能某個線程獲取了鎖但是沒有被系統進程調度分配CPU時間片。ReentrantLock除了實現Lock接口外,還定義了很多public方法來獲取鎖內部的狀態,對於鎖使用情況的監控非常有用。ReentrantLock在反序列化的時候都是沒有被鎖定的狀態,無論其在序列化時是否是鎖定狀態的。ReentrantLock允許同一個線程最多重複lock 2147483647次,超過這個次數限制就會報錯。

一、AbstractQueuedSynchronizer

      AbstractQueuedSynchronizer提供了一個實現互斥鎖,信號量等同步工具的基礎框架,基於FIFO等待隊列和一個原子更新的表示狀態的int值實現的。AbstractQueuedSynchronizer已經實現了線程阻塞以及操作等待隊列的相關方法,子類只需定義如何去修改狀態,獲取和釋放同步器時的狀態的方法即可,主要操作狀態時必須原子的,可藉助getState,setState和compareAndSetState等方法。

     AbstractQueuedSynchronizer本身並不沒有實現任何Lock相關的接口,但是提供了acquireQueued / acquireInterruptibly等方法,子類可以據此實現Lock接口。AbstractQueuedSynchronizer本身同時支持互斥模式和共享模式,但是該類本身並不關注其中的差異,而是由子類決定,通常情況下子類只支持一種模式,這時不需要定義方法來支持另一種不支持的模式。

     AbstractQueuedSynchronizer定義了一個內部類ConditionObject,該類是Condition接口的實現類,子類可以利用該類實現互斥模式。AbstractQueuedSynchronizer本身的方法並不會創建一個ConditionObject實例,他的具體語義完全由子類同步器的實現決定。

    AbstractQueuedSynchronizer的序列化實現只存儲了一個狀態值,沒有存儲等待的線程隊列,因此反序列化的時候等待的線程隊列就是空的,子類如果有這方面需要的話,必須要重寫readObject方法。

    子類繼承AbstractQueuedSynchronizer時,必須實現如下方法:

    實現這些方法必須是線程安全的,代碼比較短且是非阻塞的,AbstractQueuedSynchronizer中其他的方法都是final的,不允許被子類改寫。

1、定義

     AbstractQueuedSynchronizer繼承自AbstractOwnableSynchronizer,該類只有一個屬性,private transient Thread exclusiveOwnerThread; 表示佔有當前同步器的線程,並且定義了該屬性對應的get/set方法,如下:

    AbstractQueuedSynchronizer有兩個內部類,ConditionObject和Node,前者是public的,後者是默認的包內訪問並且static final的,前者用於實現互斥模式,後者表示等待隊列中的一個節點,後面會詳細講解這兩個內部類的實現。除此之外定義的屬性如下:

  • private transient volatile Node head;  //等待獲取鎖的鏈表頭,該鏈表簡稱同步鏈表,head和tail都是惰性初始化
  • private transient volatile Node tail;  //等待獲取鎖的鏈表尾
  • private volatile int state;  //狀態值,主要用於實現鎖重入,state等於0表示未被佔用,大於0表示累計獲取鎖的次數
  •  private static final Unsafe unsafe = Unsafe.getUnsafe();
  •  private static final long stateOffset;  //上述state屬性在AbstractQueuedSynchronizer實例中的內存偏移量
  •  private static final long headOffset; //同上,head屬性的偏移量
  •  private static final long tailOffset;  //同上,tail屬性的偏移量
  •  private static final long waitStatusOffset; //Node的waitStatus屬性在Node實例中的內存偏移量
  •  private static final long nextOffset;//Node的next屬性在Node實例中的內存偏移量

上述static屬性都是通過static代碼塊和Unsafe的方法實現,如下:

2、Unsafe objectFieldOffset和staticFieldOffset

      objectFieldOffset是一個本地方法,用來獲取實例字段在實例內存中相對於實例地址的偏移量,可據此算出存儲該屬性的內存地址,用於原子的修改該屬性。與之類似的,有一個staticFieldOffset,用來獲取靜態字段的內存偏移量,其底層實現如下:

//獲取實例字段偏移量
UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset(JNIEnv *env, jobject unsafe, jobject field))
  UnsafeWrapper("Unsafe_ObjectFieldOffset");
  
  return find_field_offset(field, 0, THREAD);
UNSAFE_END

//還有一個獲取靜態字段偏移量的方法
UNSAFE_ENTRY(jlong, Unsafe_StaticFieldOffset(JNIEnv *env, jobject unsafe, jobject field))
  UnsafeWrapper("Unsafe_StaticFieldOffset");
  return find_field_offset(field, 1, THREAD);
UNSAFE_END

jint find_field_offset(jobject field, int must_be_static, TRAPS) {
  if (field == NULL) {
    //field爲空,拋出異常
    THROW_0(vmSymbols::java_lang_NullPointerException());
  }
  
  //解析出java_lang_reflect_Field實例oop
  oop reflected   = JNIHandles::resolve_non_null(field);
  //獲取klass
  oop mirror      = java_lang_reflect_Field::clazz(reflected);
  Klass* k      = java_lang_Class::as_Klass(mirror);
  //獲取slot屬性,slot表示該字段是第幾個字段
  int slot        = java_lang_reflect_Field::slot(reflected);
  //獲取字段修飾符
  int modifiers   = java_lang_reflect_Field::modifiers(reflected);

  if (must_be_static >= 0) {
    //是否靜態字段,如果是really_is_static就等於1
    int really_is_static = ((modifiers & JVM_ACC_STATIC) != 0);
    if (must_be_static != really_is_static) {
      THROW_0(vmSymbols::java_lang_IllegalArgumentException());
    }
  }
  //獲取字段偏移量
  int offset = InstanceKlass::cast(k)->field_offset(slot);
  return field_offset_from_byte_offset(offset);
}

//獲取slot屬性
int java_lang_reflect_Field::slot(oop reflect) {
  assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
  return reflect->int_field(slot_offset);
}

inline jlong field_offset_from_byte_offset(jlong byte_offset) {
  return byte_offset;
}

3、Node

      Node表示等待隊列中的一個節點,其包含的屬性如下:

  • volatile int waitStatus; //當前Node節點的狀態
  • volatile Node prev;  //前一個Node節點
  • volatile Node next;  //下一個Node節點
  • volatile Thread thread; //關聯的線程
  • Node nextWaiter;  //用來構造一個在Condition上等待即調用await方法的Node節點鏈表,如果nextWaiter是一個常量值SHARED,則表示當前Node是共享模式

       Node定義了以下的常量值:

  • static final Node SHARED = new Node();  //表示共享模式,給nextWaiter複製
  • static final Node EXCLUSIVE = null; //表示互斥模式
  • static final int CANCELLED =  1;//以下四個都是狀態值,給waitStatus賦值,CANCELLED表示一個無效節點,對應的線程通常會退出
  • static final int SIGNAL    = -1;  //表示當前節點的下一個節點對應的線程需要被喚醒
  • static final int CONDITION = -2; //表示關聯的線程正在某個Condition上等待,當該Condition的sigal或者sigalAll方法被調用時,該節點的狀態會變成0,即初始狀態
  • static final int PROPAGATE = -3; //表示傳播狀態

       Node定義的方法比較簡單,如下:

 

isShared方法根據 nextWaiter的屬性值判斷是否共享模式,predecessor返回當前節點的前一個節點,如果爲空則拋出異常。

AbstractQueuedSynchronizer的方法比較龐雜,後面結合具體的應用場景分析。

二、ReentrantLock

       ReentrantLock的方法實現都是基於其私有屬性Sync sync,Sync的類繼承關係如下:

FairSync和NonfairSync都只提供了lock和tryAcquire方法的實現,其他實現都是公用父類Sync實現,如下:

默認的非公平鎖實現就是NonfairSync,公平鎖實現就是FairSync,構造方法的入參fair爲true,則sync初始化爲FairSync,否則是NonfairSync,參考構造方法的實現如下:

下面就來詳細探討各方法的實現細節以及公平鎖和非公平鎖下的實現差異。

1、acquireQueued

     acquireQueued用於給node節點關聯的線程搶佔鎖,如果在node前面還有其他等待的線程或者node對應的節點搶佔失敗,則進入被阻塞,進入休眠狀態,等待被喚醒;如果被喚醒了,搶佔鎖依然失敗,則繼續被阻塞,進入休眠狀態;如果上述過程有異常則將node置爲CANCELLED,關聯的thread置爲null,並將其從鏈表中移除。如果線程被喚醒是因爲被中斷則返回true,否則返回false。

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                //獲取node的前一個節點
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    //如果前一個節點是head,即當前節點是鏈表中第一個添加的節點
                    //tryAcquire爲true,表示嘗試獲取鎖成功,將node置爲head
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //如果p不等於head,說明前面還有等待獲取鎖的線程
                //如果p等於head但是獲取鎖失敗,說明有其他線程併發搶佔鎖
                //如果上述的if條件不成功,則shouldParkAfterFailedAcquire多執行幾次必定返回true
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())//parkAndCheckInterrupt返回true表示線程被中斷了
                    interrupted = true;
                //被喚醒後繼續下一次循環,如果搶佔鎖失敗,則繼續進入parkAndCheckInterrupt方法阻塞當前線程
            }
        } finally {
            //上述代碼執行過程中出現異常時,進入此邏輯
            if (failed)
                cancelAcquire(node);
        }
    }

//如果返回true,表示當前節點node需要被阻塞,通常用於for循環中
//如果p是初始的空節點,則第一遍for循環shouldParkAfterFailedAcquire返回false,第二遍返回true
//如果是正常節點且p的waitStatus大於0,第一遍for循環shouldParkAfterFailedAcquire返回false,會將中間的waitStatus大於0的節點都移除,第二遍循環時如果上一個節點的
//waitStatus就是SIGNAL則返回true,否則將其修改成SIGNAL;第三次循環判斷是SIGNAL返回true
//如果是正常節點且p的waitStatus小於0,如果waitStatus就是SIGNAL則返回true,否則將其修改成SIGNAL;第二次循環判斷是SIGNAL返回true
//綜上,無論什麼節點,最多循環三次shouldParkAfterFailedAcquire肯定返回true
 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
            //往前遍歷找到一個waitStatus不大於0的節點,將中間waitStatus小於0的節點都移除
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            //waitStatus 必須是0 or PROPAGATE,將其狀態原子的置爲SIGNAL
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

 private final boolean parkAndCheckInterrupt() {
        //將當前線程阻塞
        LockSupport.park(this);
        //線程被喚醒,判斷是否被中斷了
        return Thread.interrupted();
    }

private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;

        node.thread = null;

        //跳過所有已經被cancelled的節點,將node的prev設置爲第一個非cancelled的節點
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;

        Node predNext = pred.next;

        //修改狀態
        node.waitStatus = Node.CANCELLED;

        //如果node是tail,最後一個節點,原子的修改tail爲pred
        if (node == tail && compareAndSetTail(node, pred)) {
            //將pred的next屬性置爲null
            compareAndSetNext(pred, predNext, null);
        } else {
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                //node的前一個節點不是head,也不等於tail,應該位於衆佳麗
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    //原子的修改pred的next屬性爲next節點,即移除了node
                    compareAndSetNext(pred, predNext, next);
            } else {
                //如果pred等於head
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }

    private void unparkSuccessor(Node node) {
        
        int ws = node.waitStatus;
        if (ws < 0)
            //將其原子的修改成0
            compareAndSetWaitStatus(node, ws, 0);

        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            //從tail往前遍歷找到位於node後的最前面的一個waitStatus不大於0的節點
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }//如果if爲false就是喚醒node的下一個節點,否則喚醒位於node後的最前面的一個waitStatus不大於0的節點
        if (s != null)
            //喚醒s對應的線程
            LockSupport.unpark(s.thread);
    }

2、lock

    lock方法用於獲取鎖,如果當前線程已經獲取鎖則立即返回,如果其他線程佔有了該鎖,則當前線程會被阻塞,處於休眠狀態,當佔有該鎖的線程釋放鎖時會喚醒當前線程去搶佔鎖,如果搶佔成功則返回,否則繼續休眠。

 public void lock() {
        sync.lock();
    }

 final void lock() {
            //如果state是0,則將其原子的設置爲1,設置成功將當前線程設置爲鎖的佔有線程
            //state是0表示該鎖沒有被佔用 
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

public final void acquire(int arg) {
        if (!tryAcquire(arg) && //如果嘗試獲取鎖失敗就執行下面的acquireQueued方法,如果獲取成功則直接返回
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //acquireQueued方法會將當前線程阻塞,直到成功獲取鎖,如果該方法返回true,表示線程是因爲中斷被喚醒的
            //將當前線程中斷,實際可能已經是中斷狀態了
            selfInterrupt();
    }

//如果嘗試佔用成功返回true,否則返回false
 protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //state爲0,鎖未被佔用
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                //當前線程已經佔用了鎖
                int nextc = c + acquires;
                if (nextc < 0) // 超過int的最大值了,變成負值
                    throw new Error("Maximum lock count exceeded");
                //重置state,    
                setState(nextc);
                return true;
            }
            return false;
        }

//如果鏈表爲空則使用一個空的Node初始化鏈表,否則將目標節點插入到tail後面並修改tail,最後返回新創建的節點
 private Node addWaiter(Node mode) {
        //創建一個新的節點
        Node node = new Node(Thread.currentThread(), mode);
        Node pred = tail;
        if (pred != null) {
            //tail不爲空,即鏈表不爲空,則將新節點插入到tail的後面
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                //如果成功將tail修改成node
                pred.next = node;
                return node;
            }
            //如果tail修改失敗則進入下面的enq方法,說明有多個線程子啊修改tail
        }
        enq(node);
        return node;
    }

//如果鏈表爲空則使用一個空的Node初始化鏈表,否則不斷循環將目標節點插入到tail後面,並修改tail,直到tail修改成功爲止
private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { //鏈表爲空,將tail和head初始化成跟一個空節點
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                //將node插入到tail的後面,如果修改tail失敗則通過for循環重試,直到修改成功爲止
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

 static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }

  上述實現是非公平鎖的,公平鎖的實現如下:

final void lock() {
  //跟非公平鎖相比少了一個compareAndSetState,即不會嘗試搶佔鎖
  acquire(1);
}

protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() && //跟非公平鎖相比就多了這一個判斷,如果有等待獲取鎖的線程,則直接返回false,不去嘗試搶佔了
                    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;
        }

//如果有待處理的節點,則返回true,如果鏈表爲空則返回false
public final boolean hasQueuedPredecessors() {
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

公平鎖和非公平鎖的實現基本是一樣的,只有lock方法和tryAcquire方法的實現不一樣,公平鎖下一個新的線程不會與等待隊列中的線程競爭鎖,而是直接加入到等待隊列中,先加入隊列的線程優先獲取鎖;而非公平鎖下,一個新的線程會與等待隊列中的線程競爭鎖,沒有新線程競爭的時候纔是先加入隊列的線程優先獲取鎖,這樣就可能等待隊列中的線程一直無法獲取鎖,出現鎖飢餓等待的情形。

3、lockInterruptibly

      lock方法被中斷後還會繼續搶佔鎖直到搶佔成功爲止,lockInterruptibly被中斷後會拋出異常,並清除中斷標識;如果沒有被中斷,則會一直阻塞直到搶佔成功爲止。其實現如下:

public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        //acquire方法不會檢查是否中斷狀態    
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }

 //跟acquireQueued方法的實現一致,就一點區別,如果是因爲中斷被喚醒,前者會搶佔鎖,後者會拋出異常
 private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                 //parkAndCheckInterrupt方法返回線程是否中斷時,如果線程是中斷的則返回true,並且將中斷標識清除,即置爲false
                    parkAndCheckInterrupt())
                    //如果因爲中斷被喚醒則拋出異常
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }    

注意所謂的中斷,並不是中斷線程的正常執行,而是中斷線程的休眠或者阻塞,讓他恢復正常執行,同時將中斷標識設置爲true。測試用例如下:

@Test
    public void test() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    lock.lock();
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        while (b.isAlive()){
            b.interrupt();
            System.out.println("interrupted->"+b.isInterrupted());
            Thread.sleep(200);
        }
    }

輸出如下:

//多次中斷,不會拋出異常,繼續獲取鎖,直到獲取成功爲止
interrupted->true
interrupted->true
//被中斷後,如果thread b被喚醒了且先於main線程執行,則會把中斷標識清除
//main線程再獲取就是false
interrupted->false
interrupted->true
interrupted->true
interrupted->true
//進入sleep,被中斷後拋出異常
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at synchronizedTest.ReentrantLockTest$2.run(ReentrantLockTest.java:32)
	at java.lang.Thread.run(Thread.java:748)

 如果把上述用例中thread b的lock方法改成lockInterruptibly,則輸出如下:

interrupted->true
//被中斷後拋出異常
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at synchronizedTest.ReentrantLockTest$2.run(ReentrantLockTest.java:31)
	at java.lang.Thread.run(Thread.java:748)
//因爲沒有獲取鎖就執行unlock方法,所以拋出異常
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
	at synchronizedTest.ReentrantLockTest$2.run(ReentrantLockTest.java:36)
	at java.lang.Thread.run(Thread.java:748)

爲了避免上述的IllegalMonitorStateException異常,unlock方法解鎖時應該通過isHeldByCurrentThread判斷當前線程是否持有鎖,如果是通過lock方法加鎖則不需要了,如下:

@Test
    public void test() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    lock.lock();
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lockInterruptibly();
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if(lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            }
        });
        b.start();
        while (b.isAlive()){
            b.interrupt();
            System.out.println("interrupted->"+b.isInterrupted());
            Thread.sleep(200);
        }
    }

4、tryLock

     tryLock方法有兩個版本,不帶參數的實現和非公平鎖下tryAcquire方法的實現一致,會嘗試獲取鎖,如果獲取失敗則直接返回false,如果搶佔成功或者當前線程本身是持有鎖的則直接返回true。帶等待時間的版本,會在指定的時間內嘗試獲取鎖,如果當前線程已經是中斷的或者在等待過程中被中斷都會拋出InterruptedException異常,否則會嘗試獲取鎖直到等待的時間結束,如果時間結束未獲取鎖則返回false,獲取成功返回true。

//嘗試獲取鎖,如果獲取失敗則直接返回
public boolean tryLock() {
        //跟非公平鎖下tryAcquire方法的實現一致
    return sync.nonfairTryAcquire(1);
}

//嘗試獲取鎖,如果獲取失敗則最多等待指定的時間
public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            //如果被中斷拋出異常
            throw new InterruptedException();
        //tryAcquire嘗試獲取鎖,如果獲取成功則直接返回true,獲取失敗返回false,進入doAcquireNanos
        //doAcquireNanos會在指定的時間範圍內嘗試獲取鎖,如果被中斷則拋出異常
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }

 private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        //計算等待的截止時間    
        final long deadline = System.nanoTime() + nanosTimeout;
        //添加一個新的等待節點
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                //計算剩餘的等待時間
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                //如果需要阻塞,則剩餘時間大於spinForTimeoutThreshold,則將其阻塞
                //如果小於則直接for循環,即自旋    
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                //線程被喚醒了,檢查是否被中斷,如果是則拋出異常    
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                //如果出現異常比如上面拋出中斷異常,將node的狀態置爲cancel
                cancelAcquire(node);
        }
    }

  5、unlock

       unlock用於釋放鎖,會將state減1,如果state等於0說明之前鎖重入時調用的lock方法,都調用了對應的unlock方法,否則說明還有未調用unlock方法的,則直接返回false。如果state等於0,則喚醒head的下一個節點對應的線程並返回true,該線程被喚醒後會將該節點重置爲head。

public void unlock() {
        sync.release(1);
    }

public final boolean release(int arg) {
        //tryRelease會更新state,如果state等於0則返回true,表示需要釋放鎖,
        //如果不等於0,說明還有重入的鎖未調用unlock方法,返回false
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                //喚醒head的下一個節點對應的等待線程
                //該線程被喚醒後會將該節點重置爲head
                unparkSuccessor(h);
            return true;
        }
        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) {
                //c等於0表示所有重入的鎖都已經釋放了,返回true
                free = true;
                //將當前鎖的佔有線程設置爲null
                setExclusiveOwnerThread(null);
            }
            //設置state
            setState(c);
            return free;
        }

 6、其他方法實現總結

      其他方法的實現就比較簡單了,這裏做簡單的總結:

  • getHoldCount:如果是當前線程佔有鎖則返回state屬性,否則返回0
  • getOwner:獲取佔有當前鎖的線程,如果state爲0,則表示未被佔有,返回null
  • getQueuedThreads:獲取所有等待的線程列表,從tail開始往前遍歷,將所有節點對應的Thread加入到List中,最後返回該List
  • getQueueLength:獲取等待線程的數量,同樣是從tail往前遍歷,計數加1
  • hasQueuedThread:判斷某個線程是否在等待鏈表中,從tail開始往前遍歷,如果找到thread屬性等於目標線程的節點則返回true
  • hasQueuedThreads:判斷是否有等待的線程,即等待鏈表是否爲空
  • isHeldByCurrentThread:判斷當前線程是否佔用鎖,用佔用鎖的Thread與當前Thread比較即可
  • isLocked:判斷當前鎖是否被佔有,如果state不等於0則返回true

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章