java多线程 计数_Java多线程系列——计数器 CountDownLatch

简介:

CountDownLatch 是一个非常实用的多线程控制工具类,通常用来控制线程的等待,它可以让某个线程等待直到倒计时结束

CountDownLatch 提供了两个主要的方法,await()、countDown()。

await:使当前线程阻塞,等待计数器为 0

countDown:计数器减一,计数为零时,释放所有在等待的线程

实例:

public class CountDownLatchDemo implementsRunnable {static final CountDownLatch end = new CountDownLatch(10);static final CountDownLatchDemo demo = newCountDownLatchDemo();

@Overridepublic voidrun() {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) throwsInterruptedException {

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(intcount) {if (count < 0) throw new IllegalArgumentException("count < 0");this.sync = newSync(count);

}

其中 Sync 是 CountDownLatch 的内部类,并且 Sync 继承了 AbstractQueuedSynchronizer

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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

Sync(intcount) {

setState(count);

}intgetCount() {returngetState();

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

}protected boolean tryReleaseShared(intreleases) {//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。

State 就是 countDownLatch 中的计数器。

await()

public void await() throwsInterruptedException {

sync.acquireSharedInterruptibly(1);

}public final boolean tryAcquireSharedNanos(int arg, longnanosTimeout)throwsInterruptedException {if(Thread.interrupted())throw newInterruptedException();return tryAcquireShared(arg) >= 0 ||doAcquireSharedNanos(arg, nanosTimeout);

}

acquireSharedInterruptibly() 的作用是获取共享锁,如果当前线程处于中断状态,则抛出 InterruptedException,否则,调用 tryAcquireShared(arg) 尝试获取共享锁,如果锁计数器 = 0,则表示锁为可获取状态,返回 1,否则,锁为不可获取状态,则返回 -1。

doAcquireSharedNanos() 会使当前线程一直等待,直到当前线程获取到共享锁(或线程被中断)才返回。

countDown()

public voidcountDown() {

sync.releaseShared(1);

}public final boolean releaseShared(intarg) {if(tryReleaseShared(arg)) {

doReleaseShared();return true;

}return false;

}

releaseShared() 目的是让当前线程释放它所持有的共享锁。

tryReleaseShared() 的作用是释放共享锁,将锁计数器的值减一。

总结

CountDownLatch 是通过共享锁实现的。CountDownLatch 构造函数传递 int 参数,该参数是计数器的初始状态,表示共享锁最多能被 count 个线程同时获取。

当某线程调用 CountDownLatch 的 await 方法时,该线程会等待共享锁可用时(计数器为 0 时),才能获取共享锁,进而继续执行。

每次执行 countDown 时,会将计数器减一。

参考资料


版权声明:本文为weixin_34413326原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。