在編寫多線程的工作中,有個常見的問題:主線程(main)啟動好幾個子線程(task)來完成并發任務,主線程要等待所有的子線程完成之后才繼續執行main的其它任務。
默認主線程退出時其它子線程不會停,如果想讓main退出時其它子線程終止,可以用subThread.setDaemon(true)設置子線程為“守護線程”。
如果要在主線程等待所有子線程完成后,還要執行其它操作(比如:結果合并).可以用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類更簡潔的實現這種場景.
CountDownLatch的作用和Thread.join()方法類似,可用于一組線程和另外一組線程的協作。
例如:主線程在做一項工作之前需要一系列的準備工作,只有這些準備工作都完成,主線程才能繼續它的工作,這些準備工作彼此獨立,所以可以并發執行以提高速度。在這個場景下就可以使用CountDownLatch協調線程之間的調度了。
在直接創建線程的年代(Java5.0之前),我們可以使用Thread.join().在JUC出現后,因為線程池中的線程不能直接被引用,所以就必須使用CountDownLatch了。
CountDownLatch是能使一組線程等另一組線程都跑完了再繼續跑,CountDownLatch.await()方法在倒計數為0之前會阻塞當前線程.
實例2:CountDownLatch實現
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.
轉載請注明出處:[http://m.survivalescaperooms.com/dennisit/p/4340611.html]
新聞熱點
疑難解答