# 凍結執行緒 join()

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

在 [凍結執行緒 sleep()](/java-15/java-15-sleep.md) 中的範例，兩個執行緒（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() 來處理執行緒的排程。

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

> 執行緒與另一個執行緒 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() 結束");
   }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://java.4-x.tw/java-15/java-15-join.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
