这两JUC类适合放一起比较,随便写写,简单小结。
要点:
底层采用AQS队列,源码很简单300行。使用:
初始化对象并填入(计数器)值,例如:new CountDownLatch(3)。多线程执行完毕时,触发countdown方法将计数器值减1,当值为0时,主线程中被Latch拴住的代码开始执行。用法一:
public class CountDownLatch_v1 { //计数器设为3 static CountDownLatch latch = new CountDownLatch(3); public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread( () -> { latch.countDown(); System.out.println("T1 is OK !"); } ); Thread t2 = new Thread( () -> { System.out.println("T2 is OK !"); latch.countDown(); } ); Thread t3 = new Thread( () -> { System.out.println("T3 is OK !"); latch.countDown(); } ); t1.start(); t2.start(); t3.start(); latch.await(); //main线程阻塞中,等待t1 t2 t3都countDown后,计数器从3变为0后继续运行 System.out.println("Every T is OK !"); } }用法二:
public class CountDownLatch_v2 { static CountDownLatch latch = new CountDownLatch(1); public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread( () -> { try { latch.await(); System.out.println("T1 Beginning !"); } catch (InterruptedException e) { e.printStackTrace(); } } ); Thread t2 = new Thread( () -> { try { latch.await(); System.out.println("T2 Beginning !"); } catch (InterruptedException e) { e.printStackTrace(); } } ); Thread t3 = new Thread( () -> { try { latch.await(); System.out.println("T3 Beginning !"); } catch (InterruptedException e) { e.printStackTrace(); } } ); t1.start(); t2.start(); t3.start(); System.out.println("Start !"); latch.countDown(); } }用法场景:
Main线程等待多个线程T执行完毕后才能执行。多个线程T执行各自的代码段,执行完在线程中执行CountDown方法(减1),减到0后触发Main线程执行。Main线程等待 T1,T2 两个线程 ,只有两个线程执行达到固定次数(线程内可反复CountDown)后Main线程才能执行。为达到最大并行度,Main线程在某一时刻,启动多个线程T。 PS:new CountDownLatch(1); 多个T线程中 执行await(); //所有T线程阻塞等待。 Main线程中执行CountDown //主线程一声令下,多个T线程开始执行。情况3和1的结合,多个线程T都干完后,同时开启多个线程M做下一件事。不足:
CountDownLatch 对象New出来后只能使用一次。无法重新赋值反复使用。要点:
源码不到500,方法不多,采用RE重入锁。多个线程中通过调用barrier.await相互等待,达到触发点后,触发新线程中自定义方法执行。精髓在于Cyclic,定义的触发方法可被反复多次触发(前提:CyclicBarrier没有Broken)。使用:
CyclicBarrier构造方法中,指定触发阈值、触发方法(新线程)。达到触发次数时,开启新线程执行触发方法。子线程中调用barrier.await一次即可(写多次await调用会抛异常),然后就被绊倒了(被阻塞)。用法一:CyclicBarrier循环多次触发。
public class CyclicBarrier_v2 { static CyclicBarrier barrier ; public static void main(String[] args) throws InterruptedException { barrier = new CyclicBarrier(3, () -> { System.out.println("Every one is OK !"); }); Thread t1 = new Thread( () -> { try { for(int i=0; i <10; i++) { System.out.println("T1 is OK !"); barrier.await(); } } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } ); Thread t2 = new Thread( () -> { try { for(int i=0; i <10; i++) { System.out.println("T2 is OK !"); barrier.await(); } } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } ); Thread t3 = new Thread( () -> { try { for(int i=0; i <10; i++) { System.out.println("T3 is OK !"); barrier.await(); } } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } ); t1.start(); t2.start(); t3.start(); } }用法二:二线程交替执行。
public class CyclicBarrier_v3 { static CyclicBarrier barrier ; public static void main(String[] args) throws InterruptedException { barrier = new CyclicBarrier(1, () -> { System.out.println("A is OK !"); }); Thread t1 = new Thread( () -> { try { for(int i=0; i <10; i++) { System.out.println("T1 is OK !"); barrier.await(); } } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } ); t1.start(); } }用法场景:
多个线程执行时需要相互等待,达到等待阈值时,触发新线程执行,可反复触发。可实现2个线程交替执行。注意:
当使用CyclicBarrier做等待(await)的线程被其他线程执行Interrupt方法打断时,会抛出2个异常,InterruptedException和BrokenBarrierException,使栅栏失效。