java.util.concurrent.CountDownLatch 使用
1. 概述
CountDownLatch是java的一个并发工具(java.util.concurrent.CountDownLatch), 闭锁。
主要功能是阻塞调用其await()方法的线程,直到其他线程调用countDown()使得count(计数器)变为0时立即从await返回
2. 主要应用场景
2.1 主线程等待各子线程完成子任务再开始执行
package countDownLatch; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.CountDownLatch; public class CountDownLatchTestAllDoneNotifyMain { static CountDownLatch latch = new CountDownLatch(3); public static void main(String[] args) throws InterruptedException{ System.out.println("Time point one:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); new Thread(){ public void run(){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sub task 1 done"); latch.countDown(); } }.start(); new Thread(){ public void run(){ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sub task 2 done"); latch.countDown(); } }.start(); new Thread(){ public void run(){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sub task 3 done"); latch.countDown();// } }.start(); latch.await();//阻塞 直到构造的3变为0 System.out.println("Time point two:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); System.out.println("sub task all done, and main task running....."); } }
2.2 多个线程等待(await),被一个线程同时唤醒(countDown), 初始count为1
package countDownLatch; import java.util.concurrent.CountDownLatch; public class CountDownLatchTestOneDoneNotifyAll { private static CountDownLatch latch = new CountDownLatch(1); public static void main(String[] args) throws InterruptedException { for(int i=0; i<3; i++){ new Thread(){ public void run(){ System.out.println(Thread.currentThread().getName()+" waiting..."); try { latch.await(); System.out.println(Thread.currentThread().getName()+" running"); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); } System.out.println("Main thread do something..."); Thread.sleep(2000); System.out.println("Sub Thread begin to run..."); latch.countDown(); } }
两种场景一起测试
package countDownLatch; import java.util.concurrent.CountDownLatch; public class Driver { public static void main(String[] args) throws InterruptedException { CountDownLatch startSignal = new CountDownLatch(1); CountDownLatch doneSignal = new CountDownLatch(3); for(int i=0; i<3; i++) { new Thread(new Worker(startSignal, doneSignal)).start(); } doSomething(); startSignal.countDown(); doSomething(); doneSignal.await(); } private static void doSomething() { // TODO Auto-generated method stub } } class Worker implements Runnable{ private CountDownLatch startSignal; private CountDownLatch doneSignal; Worker(CountDownLatch startSignal, CountDownLatch doneSignal){ this.startSignal = startSignal; this.doneSignal = doneSignal; } public void run(){ try { startSignal.await(); doWork(); doneSignal.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } private void doWork() { } }
3. note
3.1 countDown()可以被一个线程执行多次,count随之减1;
3.2 在直接创建子线程使用时可以使用Thread.join()达到主线程等待子线程忙完在执行的效果,
在使用线程池等情境下, 没法直接操作线程, 可以使用CountDownLatch