Java 并发类 CountDownLatch CyclicBarrier Thread.Join 使用区别
一 .CountDownLatch
构造函数接收一个int类型的参数作为计数器,如果想等待N个点,就传入N。当调用CountDownLatch的countDown方法时,N就会减一,直至减为零。使用await方法等待,当N的值变为零,执行await的线程继续执行。
public class DemoApplication { public static void main(String[] args)throws InterruptedException, ExecutionException { SpringApplication.run(DemoApplication.class, args); //1. 定义三线程的计数器 CountDownLatch countDownLatch = new CountDownLatch(3); for(int index = 1;index<=3;index++){ //2.1 执行三个子线程 new Thread(new TaskRunnable(countDownLatch,index)).start(); } //3.先执行await 方法前的 线程等所有线程都执行完(计数器为0),再执行主线程 countDownLatch.await(); System.out.println("最后执行主线程"); } } //实现Runnable 实现 run 方法 class TaskRunnable implements Runnable{ private CountDownLatch countDownLatch; private Integer index; public TaskRunnable(CountDownLatch countDownLatch,Integer index){ this.countDownLatch = countDownLatch; this.index = index; } @Override public void run(){ //2.2 每执行一个线程 ,计数器数量减一 this.countDownLatch.countDown(); System.out.println("第 "+this.index.toString() + "个线程,执行了。"); } }
执行结果:
二.Thread.Join
Thread Join 主线程阻塞,等待该线程完成后再执行 主线程。
原理:利用while检查当前线程是否存活如果是一直阻塞wait(0)方法,当线程不存活,继续执行主线程。
public class DemoApplication { public static void main(String[] args)throws InterruptedException, ExecutionException { SpringApplication.run(DemoApplication.class, args); //Thread Join 方法 主线程阻塞,等待该线程完成后再执行 主线程。 //线程1 和线程2 是串行的。能控制线程执行顺序 Thread thread1 = new Thread(new TaskJoin("thread1")); thread1.start(); thread1.join(); Thread thread2 = new Thread(new TaskJoin("thread2")); thread2.start(); thread2.join(); System.out.println("主线程执行了!"); } } class TaskJoin implements Runnable{ private String threadName; public TaskJoin(String threadName){ this.threadName = threadName; } @Override public void run() { System.out.println(this.threadName + "子线程,执行了。"); } }
执行结果:
三 CyclicBarrier [ˈsaɪklɪk][ˈbæriə(r)]
可循环使用的屏障。它要做的事情,让一组线程到达屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会打开,所有被屏障拦截的线程才会继续运行。
默认构造方法CyclicBarrier(int parties),其参数表示屏障拦截的线程数,每个线程调用await方法告诉CyclicBarrier已经到达屏障,然后当前线程阻塞。
public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); CyclicBarrier cyclicBarrier = new CyclicBarrier(3); Thread thread1 = new Thread(new TaskJoin(cyclicBarrier,"thread1")); thread1.start(); Thread thread2 = new Thread(new TaskJoin(cyclicBarrier,"thread2")); thread2.start(); Thread thread3 = new Thread(new TaskJoin(cyclicBarrier,"thread3")); thread3.start(); } } class TaskJoin implements Runnable { private String threadName; private CyclicBarrier cyclicBarrier; public TaskJoin(CyclicBarrier cyclicBarrier,String threadName){ this.threadName = threadName; this.cyclicBarrier = cyclicBarrier; } @Override public void run() { System.out.println(this.threadName + "子线程,屏障点前执行了。"); try { this.cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println(this.threadName + "子线程,屏障点后执行了。"); } }
执行结果:
总结:
CountDownLatch:在所有线程执行完之前,阻塞的是主线程。子线程都是并行,执行完一个释放一个。但是 无法控制线程执行顺序。
Thread.Join:每个子线程都是串行的。
CyclicBarrier:所有线程未全部到达屏障点之前,线程是不释放的。