Java中CountDownLatch底層原理

CountDownLatch底層原理

CountDownLatch也是一個java.util.concurrent包中的類,能夠設置一個初始數值,在數值大於0以前讓調用await()方法的線程堵塞住,數值爲0是則會放開全部阻塞住的線程。底層基於AQS實現,還不瞭解的能夠先看這篇 Java AQS底層原理解析java

使用例子:

public static void main(String[] args) throws InterruptedException {

    // 設置初始數值爲10
    CountDownLatch latch = new CountDownLatch(10);

    // 循環中調用countDown()減1,若是調用9次則數值爲1,主線程和子線程都會阻塞,改成i<10調用10次則主線程和子線程均可以運行
    for(int i=0;i<9;i++) {
        latch.countDown();
        System.out.println(latch.getCount());
    }
    
    
    new Thread(new Runnable() {
        
        @Override
        public void run() {
            System.out.println("thread start");
            try {
                // 阻塞子線程
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread end");
        }
    }).start();
    
    // 阻塞主線程
    latch.await();
    System.out.println("main end");

}

底層原理:

  1. 構造方法segmentfault

    內部也是有個Sync類繼承了AQS,因此CountDownLatch類的構造方法就是調用Sync類的構造方法,而後調用setState()方法設置AQSstate的值。ide

    public CountDownLatch(int count) {
         if (count < 0) throw new IllegalArgumentException("count < 0");
         this.sync = new Sync(count);
     }
    
     Sync(int count) {
         setState(count);
     }
  2. await()ui

    該方法是使調用的線程阻塞住,直到state的值爲0就放開全部阻塞的線程。實現會調用到AQS中的acquireSharedInterruptibly()方法,先判斷下是否被中斷,接着調用了tryAcquireShared()方法,講AQS那篇文章裏提到過這個方法是須要子類實現的,能夠看到實現的邏輯就是判斷state值是否爲0,是就返回1,不是則返回-1。this

    public void await() throws InterruptedException {
         sync.acquireSharedInterruptibly(1);
     }
    
     public final void acquireSharedInterruptibly(int arg)
             throws InterruptedException {
         if (Thread.interrupted())
             throw new InterruptedException();
         if (tryAcquireShared(arg) < 0)
             doAcquireSharedInterruptibly(arg);
     }
    
     protected int tryAcquireShared(int acquires) {
         return (getState() == 0) ? 1 : -1;
     }
  3. countDown()線程

    這個方法會對state值減1,會調用到AQSreleaseShared()方法,目的是爲了調用doReleaseShared()方法,這個是AQS定義好的釋放資源的方法,而tryReleaseShared()則是子類實現的,能夠看到是一個自旋CAS操做,每次都獲取state值,若是爲0則直接返回,不然就執行減1的操做,失敗了就重試,若是減完後值爲0就表示要釋放全部阻塞住的線程了,也就會執行到AQS中的doReleaseShared()方法。code

    public void countDown() {
         sync.releaseShared(1);
     }
    
     public final boolean releaseShared(int arg) {
         if (tryReleaseShared(arg)) {
             doReleaseShared();
             return true;
         }
         return false;
     }
    
     protected boolean tryReleaseShared(int releases) {
         // Decrement count; signal when transition to zero
         for (;;) {
             int c = getState();
             if (c == 0)
                 return false;
             int nextc = c-1;
             if (compareAndSetState(c, nextc))
                 return nextc == 0;
         }
     }
相關文章
相關標籤/搜索