概念
- countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
- 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
源码
- countDownLatch类中只提供了一个构造器:
//参数count为计数值
public CountDownLatch(int count) { };
- 类中有三个方法是最重要的:
//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//将count值减1
public void countDown() { };
下面我们就自己来自定义实现一个CountDownLatch
代码如下:
public class KaneCountDownLatch {
private KaneCountDownLatch.Sync sync;
public KaneCountDownLatch(int count) {
this.sync = new KaneCountDownLatch.Sync(count);
}
public void countDown() {
this.sync.releaseShared(1);
}
public void await() {
this.sync.acquireShared(1);
}
class Sync extends AbstractQueuedSynchronizer {
public Sync(int count) {
this.setState(count);
}
protected int tryAcquireShared(int arg) {
return this.getState() == 0 ? 1 : -1;
}
protected boolean tryReleaseShared(int arg) {
int c;
int nextc;
do {
c = this.getState();
if (c == 0) {
return false;
}
nextc = c - 1;
} while(!this.compareAndSetState(c, nextc));
return nextc == 0;
}
}
}
测试代码如下:
public class CountDownLatch_Demo {
public static void main(String[] args) throws InterruptedException {
KaneCountDownLatch latch = new KaneCountDownLatch(6); //计数为6
for (int i = 0; i <6 ; i++) {
new Thread(()->{
System.out.println("开始准备.....");
latch.countDown();//计数减一
}).start();
Thread.sleep(1000);
}
latch.await(); //每个线程执行一次,则-1,在latch为0的时候开始向下运行 这是这些线程都准备就绪,然后去一起干同一件事
//还有一种方式, 将一个活分为多段,每个线程去干一段
// for (int i = 0; i <6 ; i++) {
// new Thread(()->{
// latch.countDown(); // 计数减一
// try {
// latch.await(); // 阻塞 -- > 0
// System.out.println("线程:"+Thread.currentThread().getName()+"执行完毕");
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }).start();
// }
System.out.println("开始干活....");
}
}
CountDownLatch和CyclicBarrier区别:
- countDownLatch是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次
- CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供reset功能,可以多次使用