看完本文,再也不怕問java線程創建的幾種方式了

  • 2019 年 10 月 4 日
  • 筆記

常規面試必問,線程創建的方式有哪幾種,那麼回答有如下幾種:
  1. 繼承Thread類
  2. 實現Runnable接口
  3. 實現Callable接口(JDK1.5+)

如果想了解具體怎麼創建的,請往下看:

繼承Thread類

//繼承Thread  public class ExtendThread extends Thread{      //線程執行體      @Override      public void run() {          //do something          System.out.println("繼承Thread創建線程");          //無返回值      }  }  public class ThreadCreateDemo {      public static void main(String[] args) {          //創建一個線程          ExtendThread extendThread = new ExtendThread();          //調用start方法啟動線程          extendThread.start();           //沒有返回值      }  }

輸出:

繼承Thread創建線程

注意

使用繼承Thread類的方法來創建線程類時候,多個線程之間是無法共享線程類的實例變量的。

實現Runnable接口

覆寫Runnable接口實現多線程可以避免單繼承局限, 當子類實現Runnable接口,此時子類和Thread的代理模式(子類負責真實業務的操作,thread負責資源調度與線程創建輔助真實業務)。

//實現Runnable接口  public class ImplRunnable implements Runnable {      //線程實行體      @Override      public void run() {          //do something          System.out.println("實現Runnable創建線程");          //沒有返回值      }  }  public class ThreadCreateDemo {      public static void main(String[] args) {          ImplRunnable implRunnable = new ImplRunnable();          Thread thread = new Thread(implRunnable);          //啟動線程          thread.start();      }  }

輸出:

實現Runnable創建線程

注意

Runnable對象僅僅作為Thread對象的target,Runnable實現類里包含的run方法僅僅作為線程的執行體,而實際的線程對象依舊是Thread實例,只是該Thread線程負責執行器target的方法。

覆寫Callable接口

//實現Callable返回值類型為Integer類型  public class ImplCallable implements Callable<Integer> {      //該call()方法將作為線程執行體,並且有返回值      @Override      public Integer call() throws Exception {          //do something          System.out.println("實現Callable接口創建線程,返回類型為Integer類型");          return 999;      }  }  public class ThreadCreateDemo {      public static void main(String[] args) throws ExecutionException, InterruptedException {          Callable<Integer> callable = new ImplCallable();          FutureTask<Integer> futureTask = new FutureTask<>(callable);          Thread thread = new Thread(futureTask);          thread.start();          //獲取返回值futureTask.get()          System.out.println(futureTask.get());      }  }

輸出:

999

注意

Callable接口有泛型限制,Callable接口裡的泛型形參類型與call方法返回值類型相同,而且Callable接口是函數式接口,因此可以使用Lambda表達式創建Callable對象。

三種方式的對比

通過繼承Thread類或者實現Runnable接口、Callable接口都可以實現多線程,不過實現Runnable接口與實現Callable接口的方式基本相同,只是Callabl接口裡定義的方法返回值,可以聲明拋出異常而已。因此將實現Runnable接口和實現Callable接口歸為一種方式。這種方式與繼承Thread方式之間的主要差別如下。

採用實現Runnable、Callable接口的方式創建線程的優缺點:

優點

線程類只是實現了Runnable或者Callable接口,還可以繼承其他類。這種方式下,多個線程可以共享一個target對象,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將CPU、代碼和數據分開,形成清晰的模型,較好的體現了面向對象的思想。

缺點

編程稍微複雜一些,如果需要訪問當前線程,則必須使用

Thread.currentThread()方法

采 用繼承Thread類的方式創建線程的優缺點:

缺點

因為線程類已經繼承了Thread類,Java語言是單繼承的,所以就不能再繼承其他父類了。

優點

編寫簡單,如果需要訪問當前線程,則無需使用

Thread.currentThread()方法,直接使用this即可獲取當前線程

鑒於上面分析,因此一般建議採用實現Runnable或Callable接口來創建多線程