在編寫多線程的工做中,有個常見的問題:主線程(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.