目录
什么是CountDownLatch
CountDownLatch是JDK提供的一个同步工具,它可以让一个或多个线程等待,一直等到其他线程中执行完成一组操作。可以用作线程同步
CountDownLatch的方法
countDown
方法
CountDownLatch在初始化时,需要给构造器指定用给定一个整数作为计数器。
CountDownLatch countDownLatch = new CountDownLatch(10);
当调用
countDown
方法时,计数器会被减1
await
方法
当调用
await
方法时,如果计数器大于0时,线程会被阻塞,一直到计数器被countDown
方法减到0时,线程才会继续执行。计数器是无法重置的,当计数器被减到0时,调用await
方法都会直接返回。
例子
实现类型LOL十个玩家加载完成后,开始游戏
public class Countdown_Latch {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(10);
CountDownLatch countDownLatch = new CountDownLatch(10);
String[] all = new String[10];
Random r = new Random();
for (int j = 0; j <10 ; j++) {
int a = j;
pool.submit(()->{
for (int i = 0; i <=100 ; i++) {
all[a] = i+"%";
try {
Thread.sleep(r.nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("\r"+Arrays.toString(all));
}
countDownLatch.countDown();
});
}
countDownLatch.await();
System.out.println("\n"+"游戏开始");
pool.shutdown();
}
}
//输出结果
[100%, 100%, 100%, 100%, 100%, 100%, 100%, 100%, 100%, 100%]
游戏开始
CountDownLatch的实现原理
CountDownLatch有一个内部类叫做Sync,它继承了AbstractQueuedSynchronizer类,其中维护了一个整数
state
,并且保证了修改state
的可见性和原子性。
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
countDown
方法源码
在 countDown
方法中,只调用了Sync实例的releaseShared
方法
public void countDown() {
sync.releaseShared(1);
}
其中的releaseShared
方法,先对计数器进行减1操作,如果减1后的计数器为0,唤醒被await方法阻塞的所有线程。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { //对计数器进行减一操作
doReleaseShared(); //如果计数器为0,唤醒被await方法阻塞的所有线程
return true;
}
return false;
}
await方法源码
在await
方法中,只调用了Sync实例的acquireSharedInterruptibly
方法
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
其中acquireSharedInterruptibly
方法,判断计数器是否为0,如果不为0则阻塞当前线程
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0) //判断计数器是否为0
doAcquireSharedInterruptibly(arg);//如果不为0则阻塞当前线程
}