Java中的CountDownLatch同步工具类使用解析
作者:niulx111
CountDownLatch同步工具类
CountDownLatch初始化的时候必须指定一个count,await方法会一直阻塞直到调用countdown方法,count为0,当count为0时,所有的等待线程都会被释放。
count是不能被重置的,如果想重复使用count,可以考虑CyclicBarrier。
CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者是线程之间的通信。
CountDownLatch可以使主线程等待子线程完成自己的任务之后在继续执行,count为线程的数量,每当线程完成一个任务后,count减一,当count为0时,表示所有的任务都已经完成,这时主线程就可以继续执行。
CountDownLatch的构造函数
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
初始化的时候必须指定一个大于等于0的count,否则会抛出异常。
Sync(int count) { setState(count); }
CountDownLatch的同步是使用了AQS的状态代表count。
看一下它的countdown方法。
/** * 如果count为0时,释放所有的等待线程 * 如果当前的count比0大就要递减 * 如果当前count为0什么也不做 */ public void countDown() { sync.releaseShared(1); }
本质还是调用了AQS的releaseShared方法。
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; } }
countdown就是释放锁的操作,每被调用一次,state就减一。首先尝试释放锁,利用CAS设置state,如果state为0,说明所有的子线程都完成了操作,这是就要唤醒在同步队列上的其他线程。
再来看一下await方法。
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; }
尝试获取锁,如果state为0,表示获取锁成功,如果state不为0,表示获取锁失败,调用doAcquireSharedInterruptibly方法阻塞直到成功获取到锁。
CountDownLatch的使用
public static void main(String[] args) throws Exception { java.util.concurrent.CountDownLatch c = new java.util.concurrent.CountDownLatch(3); ExecutorService es = Executors.newCachedThreadPool(); for (int i = 0; i < 3; i++) { es.execute(new Task(i, c)); } c.await(); System.out.println("主线程执行任务"); } public static class Task implements Runnable { private int m; private java.util.concurrent.CountDownLatch c; public Task(int m,java.util.concurrent.CountDownLatch c) { this.m = m; this.c = c; } @Override public void run() { System.out.println("子线程"+m+"完成了任务"); c.countDown(); } }
执行结果
子线程1完成了任务
子线程0完成了任务
子线程2完成了任务
主线程执行任务
在多线程中,子线程需要完成各自的任务后,主线程才能利用子线程的结果进行整合,我们可以考虑CountDownLatch来控制并发。
CountDownLatch只是一个同步辅助类,当CountDownLatch的计数器未到0之前,所有调用await的方法都会阻塞,只有计数器为0,线程才能继续往下执行。CountDownLatch的计数器是不可重用的。
到此这篇关于Java中的CountDownLatch同步工具类使用解析的文章就介绍到这了,更多相关CountDownLatch同步工具类解析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!