一、CountDownLatch
其实要完成这种某个线程等待其他线程结果才能开始任务的业务,直接在需要准备的线程中join()依赖的线程就能完成要求,但是在博客的上一篇《三个线程顺序输出》中也说到过,join的线程返回,必须是子线程已经结束。而CountDownLatch提供了更灵活的方案,可在子线程完成好其他线程依赖的工作后调用countDown()方法主动减少计数,同时继续做线程间业务无依赖的其他工作。
这里CountDownLatch只提供了一个构造方法,参数为大于0整数:
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
具体演示如下:
public class CountDownLatchTest { private static CountDownLatch counter = new CountDownLatch(2); public static void main(String[] args) throws InterruptedException { Thread threadA = new Thread(new Runnable() { @Override public void run() { System.out.println("子线程:" + Thread.currentThread().getName() + " start working!"); try { Thread.sleep(2000); counter.countDown(); System.out.println("子线程:" + Thread.currentThread().getName() + " working finish!"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "thread_A"); Thread threadB = new Thread(new Runnable() { @Override public void run() { System.out.println("子线程:" + Thread.currentThread().getName() + " start working!"); try { Thread.sleep(1000); counter.countDown(); System.out.println("子线程:" + Thread.currentThread().getName() + " working finish!"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "thread_B"); threadA.start(); threadB.start(); counter.await(); System.out.println("A、B准备就绪!"); // do something C... } }
结果:
可以看到在counter.countDown()被调用两次后,主线程便继续执行,同时子线程A、B仍可继续完成各自的工作。需要注意的是,这里初始化的计数值为2,调用2次正好返回,如果初始值为3,而实际只调用2次,那么程序就会在await()处无限等待。因此await()也提供了带等待时间的使用方法:
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); }
例如把测试程序中的await()改成如下:
counter.await(1000,TimeUnit.MILLISECONDS);
可以看到结果中,await()在没有等到计数归0,就回到主线程继续执行:
另外CountDownLatch也提供了getCount()方法随时获取当前剩余计数。
二、CyclicBarrier
译作同步屏障,提供了2种初始化方法,第一种为简单int参数:
public CyclicBarrier(int parties) { this(parties, null); }
即设定要在屏障处等待的线程数,到达预定的数目后程序即可继续往下执行。
三、二者区别