我先开多个线程处理数据,最后对这多个线程处理的结果,由一个线程进行汇总处理。那么有一个问题就是,最后这个线程要等前面全部的线程都数据处理完成(每一个线程处理的时间各不相同,结束的时间各不相同),这个线程 才开始进行处理数据。 为了处理这个解决这个线程的问题,Java语言为咱们提供了集中语言上面的机制来解决,其中有CountDownLatch类、join函数、CylicBarrier类等…… 下面我将会对CountDownLatch类和join函数这两种就最具备典型对比意义的机制进行讲解与说明的使用方法、联系与区别,CylicBarrier类的使用会在后续给出。java
CountDownLatch类使用 CountDownLatch类,一个同步辅助类,在完成一组正在其余线程中执行的操做以前,它容许一个或多个线程一直等待。并发
类中主要方 法dom
public CountDownLatch(int count);--- 减小多少个计数 public void countDown();-- -减小1个计数 public void await() throws InterruptedException---一直等待,直到计数器被减到0位置,后面 的线程才能执行 public void await(timeout,unit)throws InterruptedException---等待时间(时间数目、时间单位 时|分|秒)
方法介绍完了,直接上代码了。函数
import java.util.Random; import java.util.concurrent.CountDownLatch; public class CountDownLatchMain { public static final int THREAD_NUMB = 3;//线程个数 public static void main(String[] args) throws Throwable { CountDownLatch l = new CountDownLatch(THREAD_NUMB); for (int i = 0; i < THREAD_NUMB; i++) { new Thread(new CountDownLatchTask(l, String.valueOf(i))). start (); } l.await();//主线程等待,直到全部的线程执行完成,后面的才进行执行 System.out.println("全部线程任务都结束了,后面的任务才开始……"); Thread.sleep(new Random().nextInt(10) * 1000); System.out.println("任务结束了"); } } class CountDownLatchTask implements Runnable { private CountDownLatch latch; private String threadname; public CountDownLatchTask(CountDownLatch latch, String threadname) { this.latch = latch; this.threadname = threadname; } public void run() { try { System.out.println("线程" + this.threadname + "任务开始……"); Thread.sleep(new Random().nextInt(3) * 1000); System.out.println("线程" + this.threadname + "任务结束……"); } catch (InterruptedException e) { e.printStackTrace(); } finally { if (latch != null) { latch.countDown();//内部计算器减一 } } } }
join函数使用this
在java线程Thread类中的join函数一样具备和CountDownLatch类一样的效果来实现上述代码的功能。废话很少说,直接上代码。两个代码很是类似,惊呆了~线程
import java.util.ArrayList; import java.util.List; import java.util.Random; public class CountDownLatchMain { public static final int THREAD_NUMB = 3; public static void main(String[] args) throws Throwable { List<Thread> tList = new ArrayList<>(); for (int i = 0; i < THREAD_NUMB; i++) { Thread t = new Thread(new CountDownLatchTask(String.valueOf(i))); t.start(); tList.add(t); } for (Thread t : tList) { t.join();//这个等待其余线程执行完成后,而后在执行本线程后的任务 } System.out.println("全部线程任务都结束了,后面的任务才开始……"); Thread.sleep(new Random().nextInt(10) * 1000); System.out.println("任务结束了"); } } class CountDownLatchTask implements Runnable { private String threadname; public CountDownLatchTask(String threadname) { super(); this.threadname = threadname; } public void run() { try { System.out.println("线程" + this.threadname + "任务开始……"); Thread.sleep(new Random().nextInt(10) * 1000); System.out.println("线程" + this.threadname + "任务结束……"); } catch (InterruptedException e) { e.printStackTrace(); } } }
CountDownLatch类与join函数的联系与区别code
前面的部分谈了他们使用,下面来谈他们间的联系与区别.对象
联系:同步
他们都可以实现本文在前言中提到的场景,而且在前面使用的时候,代码也体现出来了。it
区别:
场景一
在下面这个场景中CountDownLatch类比join函数实现更好: 例如:前面多个并发的线程中的任务分为两个阶段,每个线程在第一个阶段的任务执行完成后,汇总的线程就只须要对前面全部线程第一阶段的数据进行处理,而并不关心前面并发线程的第二阶段的任务,在当前场景下join函数必需要等待前面全部的线程都执行完了后面的线程,才能执行,而CountDownLatch类实现效果更好。 代码以下
import java.util.Random; import java.util.concurrent.CountDownLatch; public class CountDownLatchMain { public static final int THREAD_NUMB = 3;// 线程个数 public static void main(String[] args) throws Throwable { CountDownLatch l = new CountDownLatch(THREAD_NUMB); for (int i = 0; i < THREAD_NUMB; i++) { new Thread(new CountDownLatchTask(l, String.valueOf(i))).start(); } l.await();// 主线程等待,直到全部的线程执行完成,后面的才进行执行 System.out.println("全部线程 1阶段 任务都结束了,后面的任务才开始……"); Thread.sleep(new Random().nextInt(10) * 1000); System.out.println("任务结束了"); } } class CountDownLatchTask implements Runnable { private CountDownLatch latch; private String threadname; public CountDownLatchTask(CountDownLatch latch, String threadname) { this.latch = latch; this.threadname = threadname; } public void run() { try { System.out.println("线程" + this.threadname + " 1阶段---任务开始……"); Thread.sleep(new Random().nextInt(3) * 1000); System.out.println("线程" + this.threadname + " 1阶段---任务结束……"); latch.countDown();// 内部计算器减一 System.out.println("线程" + this.threadname + " 2阶段---任务开始……"); Thread.sleep(new Random().nextInt(20) * 1000); System.out.println("线程" + this.threadname + " 2阶段---任务结束……"); } catch (InterruptedException e) { e.printStackTrace(); } } }
场景二
当前面执行的并发任务在线程池中执行时,想要作到前面全部的并发任务都完成后,而后再执行后面的操做,join函数就显得无能为力,而CountDownLatch类则能够解决问题。 上代码:
import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; public class CountDownLatchMain { public static final int THREAD_NUMB = 3;// 线程个数 public static void main(String[] args) throws Throwable { CountDownLatch l = new CountDownLatch(THREAD_NUMB); Executor executor = Executors.newFixedThreadPool(4);// 固定线程池 for (int i = 0; i < THREAD_NUMB; i++) { executor.execute(new CountDownLatchTask(l, String.valueOf(i))); } l.await();// 主线程等待,直到全部的线程执行完成,后面的才进行执行 System.out.println("全部线程任务都结束了,后面的任务才开始……"); Thread.sleep(new Random().nextInt(10) * 1000); System.out.println("任务结束了"); } } class CountDownLatchTask implements Runnable { private CountDownLatch latch; private String threadname; public CountDownLatchTask(CountDownLatch latch, String threadname) { this.latch = latch; this.threadname = threadname; } public void run() { try { System.out.println("线程" + this.threadname + "任务开始……"); Thread.sleep(new Random().nextInt(3) * 1000); System.out.println("线程" + this.threadname + "任务结束……"); latch.countDown();// 内部计算器减一 } catch (InterruptedException e) { e.printStackTrace(); } } }
场景三
CountDownLatch对象中的countDown()函数能够传入参数,让内部计数器提早到达0,这样后面等待的线程能够提早执行,而没必要等待剩下的线程执行完成才执行。 latch.countDown(3);// 内部计算器减三 这种场景有存在的可能,看需求……
总结 CountDownLatch类、join函数两种机制,都能起到一个或几个线程等待前面并发的线程执行完成后,在执行的功能,可是有时候在特殊场景下CountDownLatch类会有更好的用。