两个或多个线程执行完成之后继续执行之后的步骤,CountDownLatch与CyclicBarrier
开发过程中或多或少会遇到一个方法需要等待两个及以上线程执行结果,如此我们如何处理,这里java提供两个方法CountDownLatch 和CyclicBarrier 方法,以下依次举例说明:
CountDownLatch
CountDownLatch 是java.util.concurrent包下的一个方法,如下实例:
private static void testCountDownLatch() { //创建一个CountDownLatch,计数传入2,即等待两个线程完成计数为0后可继续执行 //这里注意创建必须为final 否则不能调用countDown()方法 final CountDownLatch cdl = new CountDownLatch(2); //线程1开始执行 new Thread(new Runnable() { public void run() { System.out.println("线程1开始执行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1结束"); //执行结束后计数减1 cdl.countDown(); } }).start(); //线程1开始执行 new Thread(new Runnable() { public void run() { System.out.println("线程2开始执行"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1结束"); //执行结束后计数减1 cdl.countDown(); } }).start(); try { //线程等待,当计数为0时,可继续执行 cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("继续一下步骤"); }
执行结果:
线程1开始执行 线程2开始执行 线程1结束 线程2结束 继续一下步骤
注意:
countDownLatch不可能重新初始化(final)或者修改CountDownLatch对象内部计数器的值(即不能再去重新计数或者添加计数)
CyclicBarrier
CyclicBarrier 同样是java.util.concurrent包下的一个方法,如下实例:
private static void testCyclicBarrier() { //创建一个CyclicBarrier,计数传入3,即等待两个线程完成计数为1后可继续执行 final CyclicBarrier cb = new CyclicBarrier(3); //线程1开始执行 new Thread(new Runnable() { public void run() { System.out.println("线程1开始执行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1结束"); //遇到屏障 try { cb.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }).start(); //线程1开始执行 new Thread(new Runnable() { public void run() { System.out.println("线程2开始执行"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程2结束"); //遇到屏障 try { cb.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }).start(); try { //阻塞,当计数为1时继续 cb.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println("继续一下步骤"); }
结果:同上
注意:CyclicBarrier 传递计数要比线程多一个(这里我也不知道为啥,具体感兴趣可以看源码,大体应该为需要await()3次,每次计数减1,当计数为0时可以继续执行),提供reset()方法重置,可处理更为复杂的逻辑