1.Thread.join()
如果在一個進程,如main中調用另一個thread的join()函數會導致main函數阻塞,直至thread執行完畢。
public class JoinTest {public static void main(String[] args) {System.out.println("main starts.");Thread thread = new Thread(new Runnable() {public void run() {for(int i = 0;i < 5;i++){try {System.out.println("thread" + i + " starts.");Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}});thread.start();try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("main ends.");}}
輸出結果為:
main starts.thread0 starts.thread1 starts.thread2 starts.thread3 starts.thread4 starts.main ends.
從輸出結果來看,main線程列印了main starts,執行到thread.join()被阻塞了,此時子線程開始列印log,且列印間隔為500ms,當子線程執行完畢後,main線程列印輸出main ends。
如果我們將thread.join()改成thread.join(1500),那麼輸出結果如下:
main starts.thread0 starts.thread1 starts.thread2 starts.main ends.thread3 starts.thread4 starts.
這裡採用的是join的一個重載方法,join(long millis),表示等到線程thread執行完畢或者阻塞millis時間後才能允許調用這個函數的線程繼續執行下去。從上述輸出中我們可以看出main線程並沒有等待thread執行完畢,而是等待了1500ms就繼續執行了。
其實,這裡還可以用這種方法來實現main線程等待thread線程:
//try {//thread.join();//} catch (InterruptedException e) {//e.printStackTrace();//}while(thread.isAlive()){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}
判斷thread是否處於alive狀態,如果是那麼main線程休眠100ms,如果thread結束了,main再繼續執行。
2.CountDownLatch
CountDownLatch中維護了一個計數器,初始化時接受一個整型值作為計數器初始值,其中包括兩個函數await和countDown,當在某個函數中調用await時,該線程被阻塞,沒調用一次countDown計數器值減一,只有當計數器的值為0的時候剛才被阻塞的線程才能繼續向下執行。
public class CountDownLatchTest {public static void main(String[] args) throws InterruptedException {final CountDownLatch startCdt = new CountDownLatch(5);final CountDownLatch endCdt = new CountDownLatch(5);for(int i = 0; i < 5; i++){new Thread(new Runnable(){public void run() {System.out.println(Thread.currentThread().getName() + "starts.");try {startCdt.countDown();startCdt.await();//建立的5個線程都在等startCdt的count=0才繼續往下執行} catch (InterruptedException e) {e.printStackTrace();}finally{endCdt.countDown();//每個線程執行完後都將count值減1System.out.println(Thread.currentThread().getName() + " ends.");}}}).start();}endCdt.await();//main線程當endCdt的值為0時才繼續執行,也就是等上邊建立的5個線程執行完畢後才繼續執行System.out.println("all threads end.");}
執行結果如下:
Thread-1starts.Thread-3starts.Thread-4starts.Thread-2starts.Thread-0starts.Thread-0 ends.Thread-1 ends.Thread-3 ends.Thread-4 ends.Thread-2 ends.all threads end.
儘管每個子線程建立後立刻執行,但是當他們在運行到startCdt.await()時都被阻塞了,只有startCdt的計數器的值減為0時才繼續向下執行;同理main線程在執行到endCdt.await()時阻塞,只有當其計數器減為0時才繼續執行。如果沒有endCdt.await(),那麼執行結果如下:
Thread-1starts.Thread-4starts.Thread-0starts.all threads end.Thread-2starts.Thread-3starts.Thread-3 ends.Thread-1 ends.Thread-4 ends.Thread-0 ends.Thread-2 ends.