CountDownLatch
CountDownLatch是闭锁的一种实现;CountDownLatch是在java1.5被引入;
CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
主要API:
- countDown():该方法递减计数器,表示有一个事件已经发生;
- await():该方法等待计时器达到零,达到零后表示需要等待的所有事件都已发生;
如果计数器的值非零,await方法会一直阻塞直到计数器为零,或者等待中的线程中断,或者等待超时;
起始门(Starting Gate)
所有子线程等待计数器为零后一起执行
public class Appliction {
private final static int NUM = 10;
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(1);
for (int i = 0; i < NUM; i++) {
new Thread(() -> {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println(Thread.currentThread().getName() + " started:" + System.currentTimeMillis());
}).start();
}
countDownLatch.countDown();
System.err.println("main thread exec end");
}
}
结束门(Ending Gate)
等待所有子任务或子线程结束后(计数器为零),对执行结果进行统计或汇总
/**
* 假设有10块磁盘,需要10个线程同时统计磁盘空间大小,统计完成后由主线程进行汇总
*/
public class Appliction {
private final static int NUM = 10;
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(NUM);
List<Disk> tasks = new ArrayList<>(NUM);
for (int i = 0; i < NUM; i++) {
tasks.add(new Disk());
}
for (Disk dk : tasks) {
new Thread(new DiskCountTask(countDownLatch, dk)).start();
}
countDownLatch.await();
int size = tasks.stream().mapToInt(Disk::getSize).sum();
System.err.println("All disk space size:" + size);
}
}
class Disk {
private Integer size;
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
}
class DiskCountTask implements Runnable {
private Disk disk;
private CountDownLatch downLatch;
public DiskCountTask(CountDownLatch downLatch, Disk disk) {
this.downLatch = downLatch;
this.disk = disk;
}
@Override
public void run() {
int size = new Random().nextInt(10);
try {
TimeUnit.SECONDS.sleep(size);
} catch (InterruptedException e) {
e.printStackTrace();
}
disk.setSize(size);
System.err.println(Thread.currentThread().getName() + " exec end[" + System.currentTimeMillis() + "], size:" + size);
downLatch.countDown();
}
}
设想有这样一个功能需要Thread1、Thread2、Thread3、Thread4四条线程分别统计C、D、E、F四个盘的大小,所有线程都统计完毕交给主线程去做汇总,利用CountDownLatch来完成就非常轻松