網頁

2017/10/5

Java 執行緒 Thread run()方法

Java的Thread.run()方法簡介。

Thread.run()其實是實作Runnable介面的run()。檢視Thread.run()的原始碼如下。

public class Thread implements Runnable {
    // ...
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
    //...
}

從原始碼可以看到,Thread.run()其實也只是去執行成員變數Runnable targetrun()而已,而target就是在建構Thread物件時傳入的Runnable參數。

例如建構Thread時傳入一個Runnable的實作,當呼叫Thread.run()時便會去執行Runnable.run()的實作。

public class Test {

  public static void main(String[] args) {
    
    Thread a = new Thread(new Runnable(){
      @Override
      public void run() {
        for(int i = 0; i < 5; i++) {
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
      }
    }, "Thread-a");
    
    a.run();
  }
}

所以上面的執行結果會印出

main:0
main:1
main:2
main:3
main:4

Thread.run()的原始碼來看,如果建構Thread物件時沒有傳入Runnable的實作,因為target == null,所以呼叫Thread.run()不會做任何事,例如

public class Test {

  public static void main(String[] args) {
    
    Thread a = new Thread(); 
    a.setName("Thread-a");
    a.run(); // 執行時沒有任何動作
  }
}

所以建構Thread物件時如果不傳入Runnable的實作,則應覆寫Thread.run()方法,執行緒被執行時便會執行run()的內容。

例如建立一個ThreadA類別繼承Thread並覆寫run()的內容。

public class ThreadA extends Thread {
  
  @Override
  public void run(){
    for(int i = 0; i <= 4; i++){
      System.out.println(Thread.currentThread().getName() + ":" + i);
    }
  }
}


public class Test {

  public static void main(String[] args) {
    
    Thread a = new ThreadA(); 
    a.setName("Thread-a");
    a.run();    
  }
}

執行結果如下

main:0
main:1
main:2
main:3
main:4

但在寫多執行緒程式時,並不會直接在程式中呼叫Thread.run()方法來執行,因為在程式中呼叫run()方法其實都仍只是在原本的執行緒中被執行而已,並沒有執行緒併行(concurrency)的效果。

例如下面雖然新建了兩個執行緒,但都僅是在main執行緒中被依序執行而已

public class Test {

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

執行結果如下,可以看到實際上執行緒的run()方法僅是在main執行緒中被執行。

main:0
main:1
main:2
main:3
main:4
main:0
main:1
main:2
main:3
main:4

在程式中應該呼叫Thread.start()來啟動執行緒,此時執行緒便進入可執行(Runnable)狀態,當系統要執行執行緒時便會呼叫執行緒的run()來執行。

public class Test {

  public static void main(String[] args) {
    
    Thread a = new Thread(new Runnable(){
      @Override
      public void run(){
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
      }
    }, "Thread-a");
    
    Thread b = new Thread(new Runnable(){
      @Override
      public void run(){
        for(int i = 0; i <= 4; i++){
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
      }
    }, "Thread-b"); 
    
    a.start();  // 呼叫start()始執行緒進入可執行狀態,待系統安排執行
    b.start();
    
  }
}

呼叫start()後的結果如下,可以看到此時是Thread-a及Thread-b兩條執行緒併行處理。

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

在Java 8可用lambda來寫Runnable的匿名類別。

public class Main {

    public static void main(String[] args) {

        Thread a = new Thread(() -> {
            int i = 0;
            while (i < 5) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
                i++;
            }
        }, "Thread-a");

        Thread b = new Thread(() -> {
            int i = 0;
            while (i < 5) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
                i++;
            }
        }, "Thread-b");

        a.start();
        b.start();
    }

}

不過執行緒的建立與執行建議使用Java 1.5以後的Executor各實作類別,請參考Java 使用ExecutorService來執行多執行緒

如果覺得文章有幫助的話還幫忙點個Google廣告,感恩。


參考:

沒有留言:

張貼留言