Java8 ConditionObject 源碼解析

   目錄

1、定義

         2、使用

3、await / awaitUninterruptibly

4、await / awaitNanos / awaitUntil

5、signal / signalAll

6、其他方法實現總結


      上一篇《Java8 ReentrantLock 源碼解析》中主要講解了lock和unlock相關方法的實現,本篇講解ReentrantLock的newCondition方法返回的ConditionObject實例的使用和實現細節。

1、定義

     ConditionObject是AbstractQueuedSynchronizer的一個內部類,用於實現Condition接口,ReentrantLock通過newCondition方法返回該類的一個實例,如下:

public Condition newCondition() {
        return sync.newCondition();
}

 final ConditionObject newCondition() {
            return new ConditionObject();
        }

Condition接口定義的方法如下:

這裏的await相當於Object的wait方法,signal和signalAll方法相當於Object的notify和notifyAll方法。concurrent包下各種阻塞隊列和線程池等就是Condition接口實現阻塞,以await方法的調用鏈爲例說明,如下:

  ConditionObject只有兩個屬性:

  • private transient Node firstWaiter; //在某個Condition實例上等待的Node鏈表的鏈表頭,即調用了某個condition實例的await方法的等待線程鏈表
  • private transient Node lastWaiter; //在某個Condition實例上等待的Node鏈表的鏈表尾

   注意上述鏈表是通過Node的nextWaiter構成的單向鏈表,跟通過Node的prev,next屬性構成的等待獲取鎖的同步鏈表是不一樣的,後者的鏈表頭和鏈表爲分別是AbstractQueuedSynchronizer的head和tail屬性。

    ConditionObject還定義了兩個常量,描述await方法退出時的處理方式,如下:

REINTERRUPT表示將當前線程的中斷標識重置爲true,因爲之前獲取線程是否中斷時,會將線程的中斷標識給清除掉重置爲false,此處是爲了還原;THROW_IE表示會拋出一個InterruptedException異常,表示當前線程被喚醒是因爲被中斷了。 

2、使用

     ConditionObject的await系列方法相當於Object的wait方法,signal和signalAll方法分別對應於Object的notify和notifyAll方法,跟Object一樣,執行這些方法前都需要檢查當前線程是否持有鎖,如果沒有持有則會拋出IllegalMonitorStateException異常,ConditionObject的方法和Object的對應方法的實現邏輯也大體一致,參考如下測試用例:

@Test
    public void name2() throws Exception {
        Object lock = new Object();
        Runnable a = new Runnable() {
            @Override
            public void run() {

                try {
                    System.out.println("run start,time->" + System.currentTimeMillis());
                    Thread.sleep(6000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (lock) {
                    lock.notify();
                    System.out.println("run end");
                }
            }
        };
        Thread thread = new Thread(a);
        thread.start();
        synchronized (lock) {
            System.out.println("main start,time->" + System.currentTimeMillis());
            long start = System.currentTimeMillis();
            lock.wait(1000);
            System.out.println("wait time->" + (System.currentTimeMillis() - start));
        }
        System.out.println("main end");
    }

    @Test
    public void name3() throws Exception {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Runnable a = new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println("run start,time->" + System.currentTimeMillis());
                    Thread.sleep(6000);
                    condition.signal();
                    System.out.println("run end");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };
        Thread thread = new Thread(a);
        lock.lock();
        try {
            thread.start();
            System.out.println("main start,time->" + System.currentTimeMillis());
            long start = System.currentTimeMillis();
            condition.await(1, TimeUnit.SECONDS);
            System.out.println("wait time->" + (System.currentTimeMillis() - start));
        } finally {
            lock.unlock();
        }
        System.out.println("main end");
    }

這兩個的執行結果一樣,如下:

main start,time->1585901311285
run start,time->1585901311286
run end
wait time->6001
main end

wait方法明明最多等待1s,爲啥實際等待了6s了,難道是1s後沒有被喚醒?答案是調用await和wait方法都會釋放當前佔有的鎖,然後阻塞當前線程;1s過了,阻塞的線程被喚醒了,因爲await和wait方法後面的邏輯處於加鎖的代碼塊中,所以線程被喚醒後需要重新去搶佔鎖,此時鎖是被線程thread佔用的,所以線程會被喚醒後嘗試獲取失敗又繼續被阻塞了,直到6s後thread線程釋放鎖並喚醒阻塞的main線程,main線程重新獲取鎖成功,才從await或者wait方法退出,執行下面的邏輯。

3、await / awaitUninterruptibly

     await方法用於讓當前線程阻塞,直到被喚醒或者被打斷,如果被打斷則拋出異常InterruptedException,awaitUninterruptibly會一直等待直到被喚醒,被打斷時不會拋出異常,可以通過線程的中斷標識判斷是否因爲中斷被喚醒的,注意無論是被signal喚醒的還是被中斷喚醒的,都需要再次獲取鎖纔可以退出await方法。

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        //如果線程已中斷拋出異常
        throw new InterruptedException();
    //在ConditionWaiter鏈表末尾插入一個新的狀態是CONDITION的節點    
    Node node = addConditionWaiter();
    //釋放佔有的鎖,並喚醒同步隊列中下一個等待節點,如果當前線程未持有鎖則拋出異常
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    //isOnSyncQueue判斷node是否在等待獲取鎖的同步鏈表中,對於剛創建的ConditionWaiter節點,沒有將其加入到等待獲取鎖的同步鏈表中
   //只是將其加入到通過nextWaiter屬性維護的等待鏈表中了,該方法返回false
   //等該節點被signal方法喚醒後就會將其加入到同步鏈表中了,該方法返回true
    while (!isOnSyncQueue(node)) {
        //執行park讓這個線程處於阻塞狀態
        LockSupport.park(this);
        //線程被喚醒了,如果線程被中斷的話,checkInterruptWhileWaiting的返回值就不是0,此時會退出循環,checkInterruptWhileWaiting在執行時會將當前節點加入到同步鏈表中
        //如果不是被中斷,則繼續while循環
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    //acquireQueued方法會嘗試獲取鎖,如果失敗則阻塞當前線程直到獲取成功,返回值爲true,表示最後一次喚醒是因爲線程中斷
    //interruptMode爲0或者REINTERRUPT
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        //從鏈表中移除所有非CONDITION的節點
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

public final void awaitUninterruptibly() {
            //添加一個新的節點
            Node node = addConditionWaiter();
            //釋放鎖
            int savedState = fullyRelease(node);
            boolean interrupted = false;
            //判斷node是否在同步鏈表中
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                //如果線程被中斷過將interrupted 置爲true,此時會繼續循環,直到被喚醒,node加入到同步鏈表中,while循環退出
                if (Thread.interrupted())
                    interrupted = true;
            }
            //如果獲取鎖成功或者interrupted爲true,將當前線程標記爲已中斷
            if (acquireQueued(node, savedState) || interrupted)
                selfInterrupt();
        }

       
         
//在鏈表末尾插入一個新的狀態是CONDITION的節點,因爲此時未釋放鎖,所以只有一個線程在操作waiter鏈表,不需要通過CAS修改lastWaiter屬性
private Node addConditionWaiter() {
    //獲取最後一個節點
    Node t = lastWaiter;
    //如果t不是CONDITION,則從鏈表中移除所有非CONDITION的節點
    if (t != null && t.waitStatus != Node.CONDITION) {
        unlinkCancelledWaiters();
        t = lastWaiter;
    }
    //創建一個新節點
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    if (t == null)
        //鏈表爲空
        firstWaiter = node;
    else
        //插入到lastWaiter的後面
        t.nextWaiter = node;
    //重置lastWaiter
    lastWaiter = node;
    return node;
}

//會遍歷一遍鏈表,清理掉所有不是CONDITION的節點
private void unlinkCancelledWaiters() {
    Node t = firstWaiter;
    //trail表示上一個非CONDITION節點
    Node trail = null;
    //遍歷整個鏈表
    while (t != null) {
        //獲取下一個節點
        Node next = t.nextWaiter;
        if (t.waitStatus != Node.CONDITION) {
            //將t從鏈表中移除
            t.nextWaiter = null;
            if (trail == null)
                //未找到非CONDITION節點,即之前遍歷的節點都被移除了
                firstWaiter = next;
            else
                trail.nextWaiter = next;
            if (next == null)
                //遍歷到末尾了,將tail置爲lastWaiter
                lastWaiter = trail;
        }
        else
            trail = t;
        t = next;
    }
}

    final int fullyRelease(Node node) {
        boolean failed = true;
        try {
            //獲取當前的同步器狀態
            int savedState = getState();
            //release方法返回true,表示成功釋放鎖,返回false表示不能釋放鎖
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)
                //如果release方法返回false進入此分支,將狀態置爲CANCELLED
                node.waitStatus = Node.CANCELLED;
        }
    }

   protected final int getState() {
        return state;
    }

    public final boolean release(int arg) {
        //tryRelease是子類實現的方法,會校驗當前線程是否持有鎖,如果沒有則拋出IllegalMonitorStateException異常,如果佔有了則用state減去arge,如果等於0返回true,需要釋放鎖
        if (tryRelease(arg)) {
            //獲取鏈表頭
            Node h = head;
            //waitStatus初始值是0
            if (h != null && h.waitStatus != 0)
                //喚醒下一個不是CANCELLED的節點對應的線程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
 
    //isOnSyncQueue判斷node是否在等待獲取鎖的同步鏈表中
    final boolean isOnSyncQueue(Node node) {
        //如果是CONDITION則需要從鏈表中移除
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        if (node.next != null) // If has successor, it must be on queue
            return true;
        //prev肯定不爲空,但是next可能爲空,比如該節點就是末尾節點
        return findNodeFromTail(node);
    }

    //從tail開始往前遍歷,判斷目標節點是否在鏈表中
    private boolean findNodeFromTail(Node node) {
        Node t = tail;
        for (;;) {
            if (t == node)
                return true;
            if (t == null)
                return false;
            t = t.prev;
        }
    }

    private int checkInterruptWhileWaiting(Node node) {
            return Thread.interrupted() ?
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                0;
        }

    final boolean transferAfterCancelledWait(Node node) {
        //如果狀態是CONDITION,將其原子的置爲0
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
            //如果修改成功,將其加入到同步隊列中,注意此時node還在等待鏈表中
            enq(node);
            return true;
        }
        //如果修改失敗,說明其他某個線程修改了狀態(另一個線程同時喚醒了此節點),則通過isOnSyncQueue方法判斷其
        //是否在同步隊列中,如果不在則執行yeild,不斷while循環,直到該方法返回true
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
    }

    private Node enq(final Node node) {
        //for循環直到原子修改成功爲止
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    //原子的設置head
                    tail = head;
            } else {
                //tail不爲空,將新節點插入到tail的後面
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    //如果原子的修改成功
                    t.next = node;
                    return t;
                }
            }
        }
    }


    private void reportInterruptAfterWait(int interruptMode)
            throws InterruptedException {
            if (interruptMode == THROW_IE)
                //拋出異常
                throw new InterruptedException();
            else if (interruptMode == REINTERRUPT)
                //重新中斷當前線程
                selfInterrupt();
        }

測試用例如下:

 @Test
    public void test3() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Condition condition=lock.newCondition();

        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    condition.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        //讓a線程執行起來
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    Thread.sleep(5000);
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        //讓b線程執行起來
        Thread.sleep(100);
        int i=0;
        long start=System.currentTimeMillis();
        while (a.isAlive()){
            a.interrupt();
            i++;
            Thread.sleep(10);
        }
        System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
    }

  執行結果如下:

在await方法退出前一共調用interrupt方法489次,從開始調用到await方法退出總耗時4904s,第一次調用interrupt方法會讓當前線程從while循環中退出,然後進入到acquireQueued方法嘗試獲取鎖,因爲此時線程b在休眠過程中未釋放鎖,所以進入到acquireQueued方法後會被阻塞,後面每次調用interrupt方法都會喚醒線程然後重新嘗試獲取鎖,直到獲取成功爲止,從acquireQueued方法退出。退出後因爲interruptMode是THROW_IE,然後拋出InterruptedException異常。耗時4904ms是因爲執行到start時,線程b實際已經運行了100ms左右,再過4900ms左右,就會執行signal喚醒在condition上等待的線程,線程a獲取鎖從await方法退出,main線程的while循環終止並退出。

將上述用例換成synchronized關鍵字,效果是一樣的,如下:

@Test
    public void test4() throws Exception {
        Object lock=new Object();

        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (lock) {
                        lock.wait();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        a.start();
        //讓a線程執行起來
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (lock) {
                        Thread.sleep(5000);
                        lock.notify();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        b.start();
        //讓b線程執行起來
        Thread.sleep(100);
        int i=0;
        long start=System.currentTimeMillis();
        while (a.isAlive()){
            a.interrupt();
            i++;
            Thread.sleep(10);
        }
        System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
    }

如果換成awaitUninterruptibly方法,則不會拋出異常,此時可以通過線程的中斷標識來判斷是否是因爲被中斷喚醒的,如下:

@Test
    public void test3() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Condition condition=lock.newCondition();

        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    condition.awaitUninterruptibly();
                    System.out.println("interrupted->"+Thread.currentThread().isInterrupted());
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        //讓a線程執行起來
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    Thread.sleep(5000);
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        //讓b線程執行起來
        Thread.sleep(100);
        int i=0;
        long start=System.currentTimeMillis();
        while (a.isAlive()){
            a.interrupt();
            i++;
            Thread.sleep(10);
        }
        System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
    }

測試結果如下:

4、await / awaitNanos / awaitUntil

     上面的await是沒有時間參數的,帶時間參數的await方法有三個版本,await方法被中斷喚醒後會嘗試獲取鎖並拋出異常,如果是被signal喚醒的,則返回等待時間是否超時了,返回false表示等待超時了,true表示沒有被超時。awaitNanos的實現跟await基本一致,就返回值不同,awaitNanos返回剩餘的等待時間,如果爲負值,表示等待超時了,否則未超時。awaitUntil的實現及返回值都和await一致,但是入參不同,await傳遞的是相對時間,從線程開始休眠算起,awaitUntil傳遞的是絕對時間,即具體的某一個時間點。

//返回是否因等待超時被喚醒,false表示等待超時了,true表示沒有等待超時
public final boolean await(long time, TimeUnit unit)
                throws InterruptedException {
            long nanosTimeout = unit.toNanos(time);
            if (Thread.interrupted())
                //如果線程中斷,則拋出異常
                throw new InterruptedException();
            //添加一個ConditionWaiter節點    
            Node node = addConditionWaiter();
            //釋放鎖
            int savedState = fullyRelease(node);
            //計算等待的最遲期限
            final long deadline = System.nanoTime() + nanosTimeout;
            boolean timedout = false;
            int interruptMode = 0;
            //判斷node是否在同步等待隊列中
            while (!isOnSyncQueue(node)) {
                if (nanosTimeout <= 0L) {
                    //等待的時間到了
                    timedout = transferAfterCancelledWait(node);
                    break;
                }
                //等待的時間較長,將線程park
                if (nanosTimeout >= spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                //線程被喚醒,如果線程被中斷則checkInterruptWhileWaiting返回1或者-1,終止循環
                //如果是被signal方法喚醒則檢查node是否在同步鏈表中,如果在則退出循環,嘗試獲取鎖
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
                //線程是被signal方法喚醒的,重新計算等待的時間    
                nanosTimeout = deadline - System.nanoTime();
            }
            //這部分邏輯跟不帶參數的await方法一致
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return !timedout;
        }


//awaitNanos的邏輯和帶時間參數的await方法實現一致,就是返回值不同,返回剩餘的等待時間
public final long awaitNanos(long nanosTimeout)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            final long deadline = System.nanoTime() + nanosTimeout;
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                if (nanosTimeout <= 0L) {
                    transferAfterCancelledWait(node);
                    break;
                }
                if (nanosTimeout >= spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
                nanosTimeout = deadline - System.nanoTime();
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return deadline - System.nanoTime();
        }

//跟上面兩個相比就是等待的時間不一致,上面兩個是相對時間,從進入方法開始算起的,awaitUntil是絕對時間,即一個固定的時間點
public final boolean awaitUntil(Date deadline)
                throws InterruptedException {
            long abstime = deadline.getTime();
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            boolean timedout = false;
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                if (System.currentTimeMillis() > abstime) {
                    timedout = transferAfterCancelledWait(node);
                    break;
                }
                //abstime是絕對時間
                LockSupport.parkUntil(this, abstime);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return !timedout;
        }

測試用例如下:

@Test
    public void test3() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Condition condition=lock.newCondition();
        CountDownLatch countDownLatch=new CountDownLatch(1);

        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
//                    boolean result=condition.await(6, TimeUnit.SECONDS);
//                    long result=condition.awaitNanos(TimeUnit.SECONDS.toNanos(4));
                    Calendar calendar= Calendar.getInstance();
                    calendar.add(Calendar.SECOND,5);
                    boolean result=condition.awaitUntil(calendar.getTime());
                    System.out.println("await result->"+result);
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        //讓a線程執行起來
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    Thread.sleep(5000);
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        //讓b線程執行起來
        Thread.sleep(100);
        long start=System.currentTimeMillis();
        countDownLatch.await();
        System.out.println("main thread end,time->"+(System.currentTimeMillis()-start));
    }

 5、signal / signalAll

      signal和signalAll的核心都是transferForSignal方法,區別在於前者只處理firstWaiter一個節點,而signalAll會處理所有的節點。transferForSignal方法並不會直接喚醒等待中的線程,而是將其加入到等待獲取鎖的同步鏈表的後面,然後將該節點的前一個節點的狀態改成SIGNAL,表示需要喚醒該節點。等同步鏈表前面的節點都獲取鎖並釋放鎖後,纔會讓該節點獲取鎖。

public final void signal() {
            //如果沒有獲取鎖,則拋出異常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }


public final void signalAll() {
            //如果沒有獲取鎖,則拋出異常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignalAll(first);
        }

 private void doSignal(Node first) {
            do {
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            } while (!transferForSignal(first) && //如果first是一個CANCLE節點,則transferForSignal返回false,然後通過while循環處理下一個節點
                                                  //否則返回true,終止循環
                     (first = firstWaiter) != null);
        }

final boolean transferForSignal(Node node) {
    
        //將node的狀態由CONDITION修改成0,如果修改失敗,說明不是CONDITION而是CANCLE
        //即node是一個無效節點
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;

        //將node插入到同步鏈表的末尾,返回鏈表中node的上一個節點,即插入前的tail節點
        Node p = enq(node);
        int ws = p.waitStatus;
        //如果上一個節點是CANCLE,說明當前互斥鎖未被佔用,可喚醒當前線程獲取鎖
        //將上一個tail節點狀態爲SIGNAL失敗,說明該節點就是head節點,且head節點準備釋放鎖將狀態置爲0
        //正常情形就是將p的狀態修改成SIGNAL,
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }

private void doSignalAll(Node first) {
            //first本身就是firstWaiter,所以此處可以先將lastWaiter和firstWaiter置爲null
            lastWaiter = firstWaiter = null;
            do {
                //從first開始遍歷所有的節點
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                //將目標節點加入到同步隊列中
                transferForSignal(first);
                first = next;
            } while (first != null);
        }

  測試用例如下:

 @Test
    public void test() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Condition condition=lock.newCondition();
        CountDownLatch countDownLatch=new CountDownLatch(8);
        Runnable wait=new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    lock.lock();
                    condition.await();
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName()+",await time->"+System.nanoTime());
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        };
        for(int i=0;i<5;i++){
            Thread thread=new Thread(wait);
            thread.start();
        }
        //讓上面5個線程運行起來並進入到await等待鏈表中
        Thread.sleep(2000);
        System.out.println("all wait thread start");
        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    lock.lock();
                    Thread.sleep(5000);
                    //根據awaiter隊列的順序,將await的線程加入到同步隊列中
                    condition.signalAll();
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        //讓線程a運行起來,進入sleep
        Thread.sleep(100);
        //讓線程b和線程c加入到同步隊列中
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    lock.lock();
                    System.out.println(Thread.currentThread().getName()+",lock time->"+System.nanoTime());
                    Thread.sleep(1000);
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        Thread c=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    lock.lock();
                    System.out.println(Thread.currentThread().getName()+",lock time->"+System.nanoTime());
                    Thread.sleep(1000);
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        c.start();

        countDownLatch.await();
        System.out.println("main thread end");
    }

 其輸出如下:

#從上到下,5個線程依次啓動,並依次加入到await等待鏈表中
Thread-0,start time->2257452263025112
Thread-4,start time->2257452264363671
Thread-2,start time->2257452264494532
Thread-1,start time->2257452265047514
Thread-3,start time->2257452265350669
all wait thread start
//線程b和c都起來了,進入等待鎖的同步鏈表中
Thread-6,start time->2257454364189121
Thread-7,start time->2257454364855324
//線程b和c依次獲取鎖
Thread-6,lock time->2257459262985730
Thread-7,lock time->2257460262757235
//5個線程按照加入到await等待鏈表中的順序依次被喚醒獲取鎖
Thread-0,await time->2257461362593351
Thread-4,await time->2257461462572635
Thread-2,await time->2257461562551508
Thread-1,await time->2257461662549663
Thread-3,await time->2257461762404238
main thread end

 在默認的非公平鎖下,最早加入等待獲取鎖的同步鏈表中的線程優先獲取鎖,當在某個condition實例上等待的線程被喚醒後,是加入到同步鏈表的末尾等待獲取鎖;而synchronized的實現是相反的,最近加入到同步鏈表中的線程優先獲取鎖,當在某個Object實例上等待的線程被喚醒後,是加入到同步鏈表的前面,最近才加入到等待鏈表中線程在同步鏈表中的位置越靠前。測試用例如下:
 

 @Test
    public void test2() throws Exception {
        Object lock=new Object();
        CountDownLatch countDownLatch=new CountDownLatch(8);
        Runnable wait=new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    synchronized (lock) {
                        lock.wait();
                        Thread.sleep(100);
                    }
                    System.out.println(Thread.currentThread().getName()+",await time->"+System.nanoTime());
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        for(int i=0;i<5;i++){
            Thread thread=new Thread(wait);
            thread.start();
        }
        Thread.sleep(2000);
        System.out.println("all wait thread start");
        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    synchronized (lock) {
                        Thread.sleep(5000);
                        lock.notifyAll();
                    }
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        a.start();
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    synchronized (lock) {
                        System.out.println(Thread.currentThread().getName() + ",lock time->" + System.nanoTime());
                        Thread.sleep(1000);
                    }
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        b.start();
        Thread c=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    synchronized (lock) {
                        System.out.println(Thread.currentThread().getName() + ",lock time->" + System.nanoTime());
                        Thread.sleep(1000);
                    }
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        c.start();

        countDownLatch.await();
        System.out.println("main thread end");
    }

執行結果如下:

# 5個線程依次啓動,進入等待鏈表中
Thread-0,start time->2257752210301534
Thread-1,start time->2257752211441136
Thread-4,start time->2257752213288373
Thread-2,start time->2257752213312986
Thread-3,start time->2257752214007084
all wait thread start
//線程 b和c依次啓動,進入同步鏈表中
Thread-6,start time->2257754313978574
Thread-7,start time->2257754314997979
//線程a開始釋放鎖,notifyAll將所有等待鏈表中的節點按照相反的順序加入到同步鏈表的前面
//按照同步鏈表的順序依次喚醒線程,最近加入的優先被喚醒
Thread-3,await time->2257759311780596
Thread-2,await time->2257759411766853
Thread-4,await time->2257759511758033
Thread-1,await time->2257759611688911
Thread-0,await time->2257759711730959
Thread-7,lock time->2257759711767879
Thread-6,lock time->2257760711589432
main thread end

6、其他方法實現總結

     ReentrantLock中有多個可以查看Condition等待隊列狀態的方法,其實現比較簡單,這裏總結如下:

  • getWaitingThreads:獲取在某個Condition實例上等待的線程列表,從firstWaiter開始往後遍歷,將所有狀態是CONDITION的節點對應的Thread加入到列表中並返回即可。
  • getWaitQueueLength:獲取在某個Condition實例上等待的線程的個數,遍歷方式同上,不過此方法是計數累加
  • hasWaiters:判斷在某個Condition實例上是否有等待的線程,遍歷方式同上,不過找到一個狀態是CONDITION的節點即返回true

 

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