一、简述
CountDownLatch是一个用来控制并发的很常见的工具,它是java.util.concurrent包中一个类,CountDownLatch主要提供的机制是当多个(具体数量等于初始化CountDownLatch时count参数的值)线程都达到了预期状态或完成预期工作时触发事件,其他线程可以等待这个事件来触发自己的后续工作。到达自己预期状态的线程会调用CountDownLatch的countDown方法,而等待的线程会调用CountDownLatch的await方法。
CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果想要等待N个点完成,这里就传入N。
如果某个工作线程处理的比较慢,我们不能让主线程一直等待下去。所以可以使用另外一个带指定时间的await方法----await(long time,TimeTnit unit),这个方法等待制定时间后,就不会阻塞当前线程。
注意:计数器必须大于等于0,当计数器等于0时,调用await方法不会阻塞当前线程;
二、CountDownLatch使用示例
import java.util.concurrent.CountDownLatch; public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(2);//两个线程工作 new Worker("work1", 200, latch).start(); new Worker("work2", 300, latch).start(); latch.await();//等待所有线程完成 System.out.println("工作全部完成"); } static class Worker extends Thread { String workName; int workTime; CountDownLatch latch; public Worker(String workName, int workTime, CountDownLatch latch) { this.workName = workName; this.workTime = workTime; this.latch = latch; } public void run() { System.out.println(workName + "开始工作"); doWork(); System.out.println(workName + "结束工作"); latch.countDown();//完成工作,计数器减一 } private void doWork() { try { Thread.sleep(workTime); } catch (InterruptedException e) { e.printStackTrace(); } } } }
三、与join的比较
相比于同样可以让一个线程等待子线程完成的join,CountDownLatch通过计数器提供了更灵活的控制,调用countDown方法是,N就会减1,CountDownLatch的await方法会阻塞当前线程,知道N变为0,由于countDown方法可以用在任何地方,所以这里说的N个点可以是N个线程,也可以是N个执行步骤。
而join是用于让当前线程等待JOIN线程执行结束。其实现原理是不停检查JOIN线程是否存活,如果JOIN线程存活则让当前线程永远等待。
示例如下:
import java.util.concurrent.CountDownLatch; public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(2);//两个线程工作 new Worker("work1", 200, latch).start(); new Worker("work2", 300, latch).start(); latch.await();//等待所有线程完成 System.out.println("工作全部完成"); } static class Worker extends Thread { String workName; int workTime; CountDownLatch latch; public Worker(String workName, int workTime, CountDownLatch latch) { this.workName = workName; this.workTime = workTime; this.latch = latch; } public void run() { System.out.println(workName + "开始工作"); doWork(); System.out.println(workName + "结束工作"); latch.countDown();//完成工作,计数器减一 System.out.println(workName + "开始第二阶段工作"); doWork(); System.out.println(workName + "结束第二阶段工作"); } private void doWork() { try { Thread.sleep(workTime); } catch (InterruptedException e) { e.printStackTrace(); } } } }
打印结果如下:
work1开始工作
work2开始工作
work1结束工作
work1开始第二阶段工作
work2结束工作
工作全部完成
work2开始第二阶段工作
work1结束第二阶段工作
work2结束第二阶段工作