深入理解java多線程中的join()

來源:互聯網
上載者:User
thread.Join把指定的線程加入到當前線程,可以將兩個交替執行的線程合并為順序執行的線程。比如線上程B中調用了線程A的Join()方法,直到線程A執行完畢後,才會繼續執行線程B。 

t.join();      //使調用線程 t 在此之前執行完畢。 
t.join(1000);  //等待 t 線程,等待時間是1000毫秒

 

先上一段JDK中代碼: Java代碼    /**       *  Waits at most <code>millis</code> milliseconds for this thread to         * die. A timeout of <code>0</code> means to wait forever.         */       //此處A timeout of 0 means to wait forever 字面意思是永遠等待,其實是等到t結束後。       public final synchronized void join(long millis)    throws InterruptedException {           long base = System.currentTimeMillis();           long now = 0;              if (millis < 0) {               throw new IllegalArgumentException("timeout value is negative");           }                      if (millis == 0) {               while (isAlive()) {                   wait(0);               }           } else {               while (isAlive()) {                   long delay = millis - now;                   if (delay <= 0) {                       break;                   }                   wait(delay);                   now = System.currentTimeMillis() - base;               }           }       }  

 從代碼上看,如果線程被產生了,但還未被起動,調用它的 join() 方法是沒有作用的,將直接繼續向下執行

 

Join方法實現是通過wait(小提示:Object 提供的方法)。 當main線程調用t.join時候,main線程會獲得線程對象t的鎖(wait 意味著拿到該對象的鎖),調用該對象的wait(等待時間),直到該對象喚醒main線程 ,比如退出後。這就意味著main 線程調用t.join時,必須能夠拿到線程t對象的鎖

 

Example1: Java代碼    public class JoinTest implements Runnable{              public static int a = 0;          public void run() {           for (int k = 0; k < 5; k++) {               a = a + 1;           }       }          public static void main(String[] args) throws Exception {           Runnable r = new JoinTest();           Thread t = new Thread(r);           t.start();                 System.out.println(a);       }          }  

 請 問程式的輸出結果是5嗎。答案是:有可能。其實你很難遇到輸出5的時候,通常情況下都不是5。當然這也和機器有嚴重的關係。為什麼呢。我的解釋是當主線程 main方法執行System.out.println(a);這條語句時,線程還沒有真正開始運行,或許正在為它分配資源準備運行。因為為線程分配資源需要時間,而main方法執行完t.start()方法後繼續往下執行System.out.println(a);,這個時候得到的結果是a還沒有被 改變的值0 。怎樣才能讓輸出結果為5。其實很簡單,join() 方法提供了這種功能。join() 方法,它能夠使調用該方法的線程在此之前執行完畢。 Java代碼    public static void main(String[] args) throws Exception {           Runnable r = new JoinTest();           Thread t = new Thread(r);           t.start();                 t.join(); //加入join()           System.out.println(a);       }     

 這個時候,程式輸入結果始終為5。 

為 了證明如果不使用t.join()方法,主線程main方法的System.out.println(a);語句將搶先執行,我們可以在main方法中加入一個迴圈,這個迴圈用來延長main方法執行的時間,迴圈次數將嚴重取決於機器效能。如果迴圈次數得當,我們也可以看到a的輸出結果是5。 Java代碼    public static void main(String[] args) throws Exception {           Runnable r = new JoinTest();           Thread t = new Thread(r);           t.start();                 //t.join(); //加入join()               /*               注意迴圈體內一定要有實際執行語句,否則編譯器或JVM可能最佳化掉你的這段代碼,視這段代               碼為無效。                          */               for (int i=0; i<300; i++) {                                 System.out.print(i);               }               System.out.println();           System.out.println(a);       }         

 經自己測試,最後a一直是5.

本例參考: http://agio.iteye.com/blog/210600

 

Example2:join(n) Java代碼    class RunnableImpl implements Runnable {          public void run() {           try {               System.out.println("Begin sleep");               Thread.sleep(1000);              System.out.println("End sleep");           } catch (InterruptedException e) {               e.printStackTrace();           }          }   }     Java代碼    public class JoinTest{              public static void main(String[] args) {           Thread t = new Thread(new RunnableImpl());           t.start();           try {               t.join(1000);               System.out.println("joinFinish");           } catch (InterruptedException e) {               e.printStackTrace();                }       }   }  

結果是: 
Begin sleep 
End sleep 
joinFinish

明白了吧,當main線程調用t.join時,main線程等待t線程,等待時間是1000,如果t線程Sleep 2000呢 Java代碼    class RunnableImpl implements Runnable {          public void run() {           try {               System.out.println("Begin sleep");               Thread.sleep(2000); //原來為1000              System.out.println("End sleep");           } catch (InterruptedException e) {               e.printStackTrace();           }          }   }  

結果是: 
Begin sleep 
joinFinish 
End sleep 
也就是說main線程只等1000毫秒,不管T什麼時候結束.

參考: http://blog.csdn.net/FG2006/archive/2011/05/04/6393768.aspx

 

Example3: Java代碼    class CustomThread1 extends Thread {                public void run() {             String threadName = Thread.currentThread().getName();             System.out.println(threadName + " start.");             try {                 for (int i = 0; i < 5; i++) {                     System.out.println(threadName + " loop at " + i);                     Thread.sleep(1000);                 }                 System.out.println(threadName + " end.");             } catch (Exception e) {                 System.out.println("Exception from " + threadName + ".run");             }         }     }        class CustomThread extends Thread {         CustomThread1 t1;         public CustomThread(CustomThread1 t1) {                     this.t1 = t1;         }         public void run() {             String threadName = Thread.currentThread().getName();             System.out.println(threadName + " start.");             try {                 t1.join();                 System.out.println(threadName + " end.");             } catch (Exception e) {                 System.out.println("Exception from " + threadName + ".run");             }         }     }        public class JoinTestDemo {            public static void main(String[] args) {             String threadName = Thread.currentThread().getName();             System.out.println(threadName + " start.");             CustomThread1 t1 = new CustomThread1();             CustomThread t = new CustomThread(t1);             try {                 t1.start();                 Thread.sleep(2000);                 t.start();                 t.join(); //在代碼2裡,將此處注釋掉             } catch (Exception e) {                 System.out.println("Exception from main");             }             System.out.println(threadName + " end!");         }     }   

 結果:

main start.    //main方法所在的線程起動,但沒有馬上結束,因為調用t.join();,所以要等到t結束了,此線程才能向下執行。 

[CustomThread1] Thread start.     //線程CustomThread1起動 
[CustomThread1] Thread loop at 0  //線程CustomThread1執行 
[CustomThread1] Thread loop at 1  //線程CustomThread1執行 
[CustomThread] Thread start.      //線程CustomThread起動,但沒有馬上結束,因為調用t1.join();,所以要等到t1結束了,此線程才能向下執行。 
[CustomThread1] Thread loop at 2  //線程CustomThread1繼續執行 
[CustomThread1] Thread loop at 3  //線程CustomThread1繼續執行 
[CustomThread1] Thread loop at 4  //線程CustomThread1繼續執行 
[CustomThread1] Thread end.       //線程CustomThread1結束了 
[CustomThread] Thread end.        // 線程CustomThread在t1.join();阻塞處起動,向下繼續執行的結果 

main end!      //線程CustomThread結束,此線程在t.join();阻塞處起動,向下繼續執行的結果。

 

將上例中的join注釋掉: Java代碼   

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.