Java多線程系列——計數器 CountDownLatch

簡介:

CountDownLatch 是一個很是實用的多線程控制工具類,一般用來控制線程的等待,它能夠讓某個線程等待直到倒計時結束html

CountDownLatch 提供了兩個主要的方法,await()、countDown()。多線程

  • await:使當前線程阻塞,等待計數器爲 0dom

  • countDown:計數器減一,計數爲零時,釋放全部在等待的線程ide

實例:

public class CountDownLatchDemo implements Runnable {
    static final CountDownLatch end = new CountDownLatch(10);
    static final CountDownLatchDemo demo = new CountDownLatchDemo();
    @Override
    public void run() {
        try {
            Thread.sleep(new Random().nextInt(10) * 1000);
            System.out.println("check complete...");
            end.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i = 0;i < 10;i++) {
            exec.submit(demo);
        }
        end.await();
        System.out.println("Fire!");
        exec.shutdown();
    }
}

原理解析:

countDownLatch 的計數是經過一個共享變量(volatile)實現的,下面分析它的三個核心函數:構造函數,CountDownLatch(int count);阻塞線程,await();計數器減一,countDown()。函數

CountDownLatch(int count)

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

其中 Sync 是 CountDownLatch 的內部類,而且 Sync 繼承了 AbstractQueuedSynchronizer工具

private static final class Sync extends AbstractQueuedSynchronizer {
  private static final long serialVersionUID = 4982264981922014374L;

  Sync(int count) {
    setState(count);
  }

  int getCount() {
    return getState();
  }

  protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
  }

  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;
    }
  }
}
View Code

其中 setState 是設置 AbstractQueuedSynchronizer 中 state 變量,該變量聲明瞭 volatile。post

State 就是 countDownLatch 中的計數器。ui

await()

public void await() throws InterruptedException {
  sync.acquireSharedInterruptibly(1);
}
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
      throws InterruptedException {
  if (Thread.interrupted())
    throw new InterruptedException();
  return tryAcquireShared(arg) >= 0 ||
    doAcquireSharedNanos(arg, nanosTimeout);
}

acquireSharedInterruptibly() 的做用是獲取共享鎖,若是當前線程處於中斷狀態,則拋出 InterruptedException,不然,調用 tryAcquireShared(arg) 嘗試獲取共享鎖,若是鎖計數器 = 0,則表示鎖爲可獲取狀態,返回 1,不然,鎖爲不可獲取狀態,則返回 -1。this

doAcquireSharedNanos() 會使當前線程一直等待,直到當前線程獲取到共享鎖(或線程被中斷)才返回。url

countDown()

public void countDown() {
  sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
  if (tryReleaseShared(arg)) {
    doReleaseShared();
    return true;
  }
  return false;
}

releaseShared() 目的是讓當前線程釋放它所持有的共享鎖。

tryReleaseShared() 的做用是釋放共享鎖,將鎖計數器的值減一。

總結

CountDownLatch 是經過共享鎖實現的。CountDownLatch 構造函數傳遞 int 參數,該參數是計數器的初始狀態,表示共享鎖最多能被 count 個線程同時獲取。

當某線程調用 CountDownLatch 的 await 方法時,該線程會等待共享鎖可用時(計數器爲 0 時),才能獲取共享鎖,進而繼續執行。

每次執行 countDown 時,會將計數器減一。

參考資料

Java多線程系列--「JUC鎖」09之 CountDownLatch原理和示例

 
相關文章
相關標籤/搜索