java創建線程的四種方法


第一種:  通過繼承Thread類創建線程

第二種: 通過實現Runnable接口創建線程

這兩種早已爛記於心,這里就不作過多的介紹, 主要介紹其源碼

Thread類 implements Runnable

thread空線程的run方法 是判斷target是否存在實,再執行target實例中的run方法

public void run(){
    if(this.target != null){
           this.target.run();
     }
}

通過實現Runnable接口, 並且通過thread構造函數創建線程的方法

Runnable runnable = new Runnable(){...重寫run方法};

Thread thread_one = new Thread(runnable);
Thread thread_two = new Thread(runnable);

如果創建多個線程, 實質是多個線程引用同一個target 實例

對比兩種方式的區別:

  通過繼承Thread類實現多線程的方式由於單繼承的局限性, 不能再繼承其他類, 只能完成各自的任務

  通過實現Runnable接口實現多線程的方式能更好的做到並發完成同一個任務, 因為訪問的是同一個target, 實現了共享數據

總之,在大多數情況下,都偏向於通過實現Runnable接口創建多線程

 

第三種: 使用Callable接口 和 FutureTask類創建線程

由於Thread類和Runnbale接口中的run方法沒有返回值, 所以這兩種方式不能獲取異步執行的結果

Callable接口

package java.util.concurrent;
@FunctionalInterface
public interface Callable<V>{
    V call() throws Exception;
}

@FunctionalInterface 注解標注在接口上, 表示此接口為"函數式接口"

函數式接口:  只有一個抽象方法的接口

此注解只是方便編譯器進行檢查, 不加也不會影響. 如果加了注解但該接口不是函數式接口,編譯器會報錯

Callable接口是泛型接口 ,也是函數式接口

call()抽象方法還有一個Exception的異常聲明, 容許方法內的異常直接拋出,並且可以不予捕獲

 

 

 

 

Future接口, RunnableFuture接口,以及FutureTask實現類都是位於 java.util.concurrent包下

V get()  用於阻塞性得到異步執行的結果.  此方法是阻塞性的,異步未執行完會處於阻塞狀態

Object outcome  用於保存call()方法的異步執行結果.  get()會獲取

創建線程的具體步驟

class ReturnableTask implements Callable<Long>{
      public long call() throws Exception{
             //線程要執行的代碼
     }      
}    

public static void main(String args[]) throws InterruptedException{
    ReturnableTask task  = new new ReturnableTask();
     Futuretask<Long> FutureTask = new Futuretask<Long>(task);
    Thread thread = new Thread(FutureTask,"returnableThread");  
    thread.start();
    System.out.println(FutureTask.get());   //得到異步執行結果
}

下圖為具體實現過程

 

 

 兩個線程處於並發狀態, 默認異步執行

看起來兩個線程是同時進行,實質上是不是, 單個進程在同一時間只能執行一個進程,由於分給線程的時間片非常短(線程切換毫秒級),所以以為是同時

並發執行的消息通信機制分為同步和異步,  這些就不做過多解釋

總之,圖上的兩個線程不是同時運行

 

第四種: 通過線程池創建線程

通過Thread創建線程在執行完就被銷毀了, 不可服用. 在高並發場景中, 頻繁創建線程是非常消耗資源的, 通過線程池創建線程可以對已經創建好的線程進行復用

Executors 靜態工廠類  用於創建不同的線程池 java.util.concurrent;

//創建一個包含三個線程的線程池
private static ExecutorService pool = Executors.newFixedThreadPool(3);

Executor接口

  void executo(Runnable command);    //執行Runnable類型

ExecutorService<T> extends Executor

  <T> Future<T> submit(Callable<T> task)   //提交callable類型以執行

  Future<?> submit(Runnable task)      //提交Runnable類型以執行

具體實現

main
Future future  = pool.submit(new RuturnableTask());
Long result = (Long) future.get();     //得到異步執行的結果

execute() 與 submit() 執行線程方法的區別

execute()只能執行Runnable, 並且無返回值

submit() 既能執行Runnable又能執行callable, 並且有返回值

注: 實際生產環境中禁止使用Executors創建線程池

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM