併發、並行傻傻分不清楚?執行緒的一生都經歷些什麼?

顧林海發表於2019-01-29

人生一切難題,知識給你答案

溫馨提示:閱讀本文需要5-6分鐘(少量程式碼)
公眾號:顧林海(每天更新優質文章)


今天,我們來解決一個問題:

併發、並行傻傻分不清楚?執行緒的一生都經歷些什麼?

人生一切難題,知識給你答案。


==併發與並行==

併發是指在某個時間段內,多工交替處理的能力。並行是指同時處理多工的能力。

案例:商場銷售員需要面對多位顧客時,有的顧客問價格,有的顧客問質量,這時銷售員需要不斷的回答顧客,中間不停的切換話題並記住之前的話題,方便回過頭回答,這種方式可以理解為併發,如果有多位銷售員對應多位顧客,多位銷售員同時回答顧客問題,這種方式就是並行。

==執行緒的生命週期==

執行緒是CPU排程和分配的基本單位。執行緒可以擁有自己的操作棧、程式計數器、區域性變數表等資源,它與同一程式內的其他執行緒共享該程式的所有資源。

執行緒的建立有三種方式,第一種是繼承自Thread類,如下所示:

public class HandlerThread extends Thread {
    
    @Override
    public void run() {
        
    }
    
}
複製程式碼

第二種方式是實現Runnable介面,如下所示:

public class HandlerThread implements Runnable {

    @Override
    public void run() {

    }

}
複製程式碼

推薦使用第二種方式,因為繼承Thread類不符合里氏替換原則,實現Runnable介面可以使程式設計更加靈活,對外暴露的細節比較少。

第三種方式使用Callable介面,如下所示:

public class Demo implements Callable<String> {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> callable=new Demo();
        FutureTask<String> futureTask=new FutureTask<>(callable);
        new Thread(futureTask).start();
        System.out.println(futureTask.get());
    }

    @Override
    public String call() throws Exception {
        return "demo";
    }
}
複製程式碼

Callable和Future介面的區別在於:

  • Callable規定的方法是call(),而Runnable規定的方法是run().
  • Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。
  • call()方法可丟擲異常,而run()方法是不能丟擲異常的。
  • 執行Callable任務可拿到一個Future物件, Future表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future物件可瞭解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。
  • Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它執行緒執行的任務。

執行緒的生命週期有五種狀態,如下圖:

執行緒五種狀態.jpg

執行緒的生命週期的狀態有:新建狀態、就緒狀態、執行狀態、阻塞狀態以及終止狀態。

  • new,新建狀態,是執行緒被建立且未啟動的狀態。
  • Runnable,就緒狀態,是呼叫start()方法之後執行之前的狀態,start()不能被多次呼叫,否則會丟擲IllegalStateException異常。
  • Running,執行狀態,是run()正在執行時執行緒的狀態。執行緒可能會由於某些因素而推出Running,如時間、異常、鎖、排程等。
  • Blocked,阻塞狀態,進入此狀態的情況包括:同步阻塞(鎖被其他執行緒佔用)、主動阻塞(呼叫Thread的某些方法,主動讓出CPU執行權,比如sleep()、join()等)以及等待阻塞(執行了wait()方法)。
  • Dead,終止狀態,是run()執行結束,或因異常退出後的狀態。

838794-506ddad529df4cd4.webp.jpg

相關文章