網頁

2017/10/6

Java 執行緒 Thread.join()

Java執行緒的Thread.join()方法可以讓目前正在執行的執行緒暫停,直到呼叫join()的執行緒執行結束才會繼續執行。


例如下面範例,在Thread-b進入run()後便呼叫Thread-a物件的join(),因此Thread-b會暫停執行,直到Thread-a執行結束為止。

public class Test {

  public static void main(String[] args) {
    
    Thread a = new Thread(new Runnable(){
      @Override
      public void run(){
        System.out.println(Thread.currentThread().getName() + ":start");
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        System.out.println(Thread.currentThread().getName() + ":end");
      }
    }, "Thread-a"); 
    
    Thread b = new Thread(new Runnable(){
      @Override
      public void run(){
        System.out.println(Thread.currentThread().getName() + ":start");
        try {
          a.join(); // Thread-b暫停直到Thread-a執行結束才會繼續執行
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        System.out.println(Thread.currentThread().getName() + ":end");
      }
    }, "Thread-b"); 
    
    a.start();
    b.start();
    
  }
}

執行結果

Thread-a:start
Thread-b:start
Thread-a:0
Thread-a:1
Thread-a:2
Thread-a:3
Thread-a:4
Thread-a:end
Thread-b:0
Thread-b:1
Thread-b:2
Thread-b:3
Thread-b:4
Thread-b:end

執行順序圖:


要注意的是,被暫停的只有那條正在執行並呼叫另一條執行緒物件的join()的執行緒而已,其他執行緒不受影響。例如上面範例等待Thread-a執行結束的只有Thread-b而已。

承上,再多加另一條執行緒Thread-c來執行。

public class Test {

  public static void main(String[] args) {
    
    Thread a = new Thread(new Runnable(){
      @Override
      public void run(){
        System.out.println(Thread.currentThread().getName() + ":start");
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        System.out.println(Thread.currentThread().getName() + ":end");
      }
    }, "Thread-a"); 
    
    Thread b = new Thread(new Runnable(){
      @Override
      public void run(){
        System.out.println(Thread.currentThread().getName() + ":start");
        try {
          a.join(); // Thread-b暫停直到Thread-a執行結束才會繼續執行
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        System.out.println(Thread.currentThread().getName() + ":end");
      }
    }, "Thread-b"); 
    
    Thread c = new Thread(new Runnable(){
      @Override
      public void run(){
        System.out.println(Thread.currentThread().getName() + ":start");
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        System.out.println(Thread.currentThread().getName() + ":end");
      }
    }, "Thread-c"); 
    
    a.start();
    b.start();
    c.start();
    
  }
}

從下面的執行結果可以看到Thread-b在等到Thread-a執行結束才會繼續執行,但Thread-c不受影響。

Thread-a:start
Thread-b:start // <--接著呼叫a.join(),Thread-b暫停
Thread-a:0
Thread-a:1
Thread-c:start
Thread-a:2
Thread-c:0
Thread-a:3
Thread-c:1
Thread-a:4
Thread-c:2
Thread-a:end   // <--Thread-a執行結束
Thread-c:3
Thread-c:4
Thread-c:end
Thread-b:0
Thread-b:1
Thread-b:2
Thread-b:3
Thread-b:4
Thread-b:end

如果將第一個範例的a.join()改在main()中呼叫如下,會發現Thread-b不會暫停了,因為暫停執行的是main執行緒。

public class Test {

  public static void main(String[] args) {
    
    Thread a = new Thread(new Runnable(){
      @Override
      public void run(){
        System.out.println(Thread.currentThread().getName() + ":start");
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        System.out.println(Thread.currentThread().getName() + ":end");
      }
    }, "Thread-a"); 
    
    Thread b = new Thread(new Runnable(){
      @Override
      public void run(){
        System.out.println(Thread.currentThread().getName() + ":start");
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        System.out.println(Thread.currentThread().getName() + ":end");
      }
    }, "Thread-b"); 
    
    a.start();
    b.start();
    try {
      a.join();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    
  }
}

Thread.join()會拋出InterruptedException例外,必須用try-catch捕捉。

join()只有在執行緒存活時才有作用。

沒有留言:

張貼留言