# 凍結執行緒 join()

在 [執行緒生命週期](https://java.4-x.tw/java-15/java-15-4) 中，被凍結的狀態提到的 sleep() 已在 [凍結執行緒 sleep()](https://java.4-x.tw/java-15/java-15-sleep) 說明了用法，本篇將說明 join() 的用法。

在 [凍結執行緒 sleep()](https://java.4-x.tw/java-15/java-15-sleep) 中的範例，兩個執行緒（apple, pen）可說是同時啟動的，那如果再啟動的下方再加上一行印出 main() 結束 的程式碼

```
apple.show();
pen.show();
System.out.println("main() 結束");
```

## 完整程式碼(錯誤)

```
class multi_Test
{
   private String name;
   public multi_Test(String str)
   {
      name=str;
   }
   public void show()
   {
      for(int i=0;i<3;i++)
      {
         try
         {
            sleep((int)(1000*Math.random()));
         }
         catch(InterruptedException e){}
         System.out.println(name);
      }
   }
}

public class multi_thread_3
{
   public static void main(String args[])
   {
      multi_Test apple=new multi_Test("apple");
      multi_Test pen=new multi_Test("pen");
      apple.start();
      pen.start();
      System.out.println("main() 結束");
   }
}
```

當我們執行的結果會發現，會先印出「main() 結束」。

> 記得 main() 本身其實也是個執行緒，一樣是看誰先搶到資源。\
> 但因為僅印出字串，不需要經過執行緒的啟動，因此通常較先搶到資源 先執行。

這麼一來若是先印出「 main() 結束」 就不是我們想要的目的；\
我們想先apple 執行緒完成後再執行pen 執行緒，\
等到兩個執行緒都結束才正式main() 結束（因此印出字串）。

想要達到這樣的結果，就必須使用到 join() 來處理執行緒的排程。

在 [執行緒生命週期](https://java.4-x.tw/java-15/java-15-4) 中提到的觀念：

> 執行緒與另一個執行緒 join() 一起時：\
> 當有其他執行緒呼叫 join()，原來正執行的執行緒（或程式碼）會先暫停

join() 必須寫在 try-catch 區塊內，因此我們可以將上述錯誤的程式這樣改寫：

當 apple 執行緒啟動 便進到try 後，apple執行緒結束後就會往下執行 啟動pen執行緒，\
當pen 執行緒結束後 才會再往下執行 印出字串的程式。

```
apple.start();
try
{
   apple.join();
   pen.start();
   pen.join();
}
catch(){}
System.out.println("main() 結束");
```

在啟動 apple 執行緒後會先停留在 apple.join() 等待該執行緒完成，才會執行下一行程式（啟動pen執行緒）；\
同理 pen 執行緒會停留在 pen.join() ，等到執行緒結束後就會將字串「main() 結束」字串印出。

還有一點要注意的是， join() 會拋出 InterruptedException 例外\
因此才必須將 join() 寫在 try-catch 區塊，而catch 要捕捉 InterruptedException 例外。

```
apple.start();
try
{
   apple.join();
   pen.start();
   pen.join();
}
catch(InterruptedException e){}
System.out.println("main() 結束");
```

## 完整程式碼(正確)

```
class multi_Test
{
   private String name;
   public multi_Test(String str)
   {
      name=str;
   }
   public void show()
   {
      for(int i=0;i<3;i++)
      {
         try
         {
            sleep((int)(1000*Math.random()));
         }
         catch(InterruptedException e){}
         System.out.println(name);
      }
   }
}

public class multi_thread_3
{
   public static void main(String args[])
   {
      multi_Test apple=new multi_Test("apple");
      multi_Test pen=new multi_Test("pen");
      apple.start();
      try
      {
         apple.join();
         pen.start();
         pen.join();
      }
      catch(InterruptedException e){}
      System.out.println("main() 結束");
   }
}
```
