在编写多线程的工做中,有个常见的问题:主线程(main) 启动好几个子线程(task)来完成并发任务,主线程要等待全部的子线程完成以后才继续执行main的其它任务。html
默认主线程退出时其它子线程不会停,若是想让main退出时其它子线程终止,能够用subThread.setDaemon(true) 设置子线程为“守护线程”。java
若是要在主线程等待全部子线程完成后,还要执行其它操做(好比:结果合并).能够用join()方法来等待全部子线程完成后,才继续执行。以下:多线程
实例1:Join实现并发
public class TestRunnable implements Runnable{ /** 线程名 */
private String threadName; public TestRunnable(String threadName) { this.threadName = threadName; } @Override public void run() { System.out.println( "[" + threadName + "] Running !" ); } public static void main(String[] args) throws InterruptedException { List<Thread> lists = new ArrayList<Thread>(); for(int i=0; i<5; i++){ Thread thread = new Thread(new TestRunnable("子线程" + (i + 100))); lists.add(thread); thread.start(); } System.out.println("主线程阻塞,等待全部子线程执行完成"); for(Thread thread : lists){ // 若是注释掉thread.join(),启动后 main线程 与 全部子线程 thread并发工做,并不会等待子线程完成后再执行
thread.join(); } System.out.println("全部线程执行完成!"); } }
此外能够用java.util.concurrent.CountDownLatch类更简洁的实现这种场景.ide
CountDownLatch 的做用和 Thread.join() 方法相似,可用于一组线程和另一组线程的协做。this
例如:主线程在作一项工做以前须要一系列的准备工做,只有这些准备工做都完成,主线程才能继续它的工做,这些准备工做彼此独立,因此能够并发执行以提升速度。在这个场景下就可使用 CountDownLatch 协调线程之间的调度了。spa
在直接建立线程的年代(Java 5.0 以前),咱们可使用 Thread.join().在 JUC 出现后,由于线程池中的线程不能直接被引用,因此就必须使用 CountDownLatch 了。线程
CountDownLatch 是能使一组线程等另外一组线程都跑完了再继续跑 ,CountDownLatch.await() 方法在倒计数为0以前会阻塞当前线程.3d
实例2:CountDownLatch实现
code
public class TestRunnable implements Runnable{ /** 处理main线程阻塞(等待全部子线程) */
private CountDownLatch countDown; /** 线程名字 */
private String threadName; public TestRunnable(CountDownLatch countDownLatch, String threadName) { this.countDown = countDownLatch; this.threadName = threadName; } @Override public void run() { System.out.println( "[" + threadName + "] Running ! [countDownLatch.getCount() = " + countDown.getCount() + "]." ); // 每一个独立子线程执行完后,countDownLatch值减1
countDown.countDown(); } public static void main(String [] args) throws InterruptedException { int countNum = 5; CountDownLatch countDownLatch = new CountDownLatch(countNum); for(int i=0; i<countNum; i++){ new Thread(new TestRunnable(countDownLatch,"子线程" + (i+100))).start(); } System.out.println("主线程阻塞,等待全部子线程执行完成"); //endLatch.await()使得主线程(main)阻塞直到endLatch.countDown()为零才继续执行
countDownLatch.await(); System.out.println("全部线程执行完成!"); } }
执行结果:
对于countDownLatch咱们须要注意:CountDownLatch.await() 方法在倒计数为0以前会阻塞当前线程.
a)在不适用await()的时候:
执行结果以下:
此时咱们看到,主线程和子线程并发执行,主线程执行完后子线程还在执行,没有实现咱们须要的场景.
b)CountDownLatch.await() 方法在倒计数不为0时
执行结果:
如图,能够看到,子线程执行完成了,可是countDownLatch的倒记数的值不为0,进入持续等待中,并无唤醒主线程来执行.因此countDownLatch.await()生效必须保证计数值变为0.