您的位置:首页 > 编程语言 > Java开发

Java并发编程札记-(四)JUC锁-08CountDownLatch

2017-12-17 20:18 411 查看
CountDownLatch是一个通用同步器,用于同步一个或多个任务。在完成一组正在其他线程中执行的任务之前,它允许一个或多个线程一直等待。

可以用一个初始计数值来初始化CountDownLatch对象,任何在这个对象上调用wait()的方法都将阻塞,直至计数值到达0。每完成一个任务,都可以在这个对象上调用countDown()减少计数值。当计数值减为0,所有等待的线程都会被释放。CountDownLatch的计数值不能重置。如果需要重置计数器,请考虑使用CyclicBarrier。

使用场景

作为一个通用同步工具,CountDownLatch有许多用途。比如,将计数值初始化为1的CountDownLatch用作一个简单的开/关:在通过调用countDown()的线程打开入口前,所有调用await()的线程都一直在入口处等待;用N初始化的 CountDownLatch可以使一个线程在N个线程完成某项操作之前一直等待,或者使其在某项操作完成N次之前一直等待。

例1:CountDownLatch作为开关

public class Driver {
public static void main(String args[]) throws InterruptedException {
int n = 5;
// 启动信号,在driver为继续执行worker做好准备之前,它会阻止所有的worker继续执行。
CountDownLatch startSignal = new CountDownLatch(1);
// 完成信号,它允许driver在完成所有 worker之前一直等待。
CountDownLatch doneSignal = new CountDownLatch(n);

for (int i = 0; i < n; ++i) // 创建并启动所有线程
new Thread(new Worker(startSignal, doneSignal)).start();

Thread.sleep(1000);

startSignal.countDown(); // 打开startSignal开关,执行所有等待的任务

doneSignal.await();// 等待doneSignal计数器为0,即所有任务执行完

System.out
4000
.println("down");
}
}

class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;

Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}

public void run() {
try {
System.out.println(Thread.currentThread().getName() + "启动了");
startSignal.await();// 使当前线程在锁存器startSignal倒计数至零之前一直等待
System.out.println(Thread.currentThread().getName() + "工作了");
doneSignal.countDown();// 递减锁存器doneSignal的计数
} catch (InterruptedException ex) {
}
}
}


执行结果为:

Thread-2启动了

Thread-0启动了

Thread-1启动了

Thread-3启动了

Thread-4启动了

Thread-2工作了

Thread-3工作了

Thread-1工作了

Thread-4工作了

Thread-0工作了

down

从结果中看到,5个任务线程依次启动,但每一个都没有执行完,这是因为run方法中的
startSignal.await();
使当前线程在锁存器startSignal倒计数至零之前一直等待。直到
startSignal.countDown();
打开startSignal开关,才执行所有等待的任务。

例2:CountDownLatch分割任务

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Driver2 {
public static void main(String args[]) throws InterruptedException {
int n = 5;
ExecutorService exec = Executors.newCachedThreadPool();
// 完成信号,它允许driver在完成所有 worker之前一直等待。
CountDownLatch doneSignal = new CountDownLatch(n);
// 创建并启动所有线程
for (int i = 0; i < n; ++i)
exec.execute(new WorkerRunnable(doneSignal, i));
// 等待doneSignal计数器为0,即所有任务执行完
doneSignal.await();
System.out.println("down");
exec.shutdown();
}
}

class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;

WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}

public void run() {
System.out.println("任务" + i + "完成了");
doneSignal.countDown();// 递减锁存器doneSignal的计数
}
}


源码

待补充

本文就讲到这里,想了解Java并发编程更多内容请参考:

Java并发编程札记-目录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: