天天看點

【Java】什麼是線程?Thread和Runnable差別

1.1 多線程原理

昨天的時候我們已經寫過一版多線程的代碼,很多同學對原理不是很清楚,那麼我們今天先畫個多線程執行時序圖

來展現一下多線程程式的執行流程。

代碼如下:

自定義線程類:

【Java】什麼是線程?Thread和Runnable差別
【Java】什麼是線程?Thread和Runnable差別

測試類:

【Java】什麼是線程?Thread和Runnable差別

流程圖:

【Java】什麼是線程?Thread和Runnable差別

程式啟動運作 main 時候,

java

虛拟機啟動一個程序,主線程

main

main()

調用時候被建立。随着調用

mt

的對象的

start 方法,另外一個新的線程也啟動了,這樣,整個應用就在多線程下運作。

通過這張圖我們可以很清晰的看到多線程的執行流程,那麼為什麼可以完成并發執行呢?我們再來講一講原理。

多線程執行時,到底在記憶體中是如何運作的呢?以上個程式為例,進行圖解說明:

多線程執行時,在棧記憶體中,其實 每一個執行線程都有一片自己所屬的棧記憶體空間

。進行方法的壓棧和彈棧

【Java】什麼是線程?Thread和Runnable差別

當執行線程的任務結束了,線程自動在棧記憶體中釋放了。但是當所有的執行線程都結束了,那麼程序就結束了

1.2 Thread類

在上一天内容中我們已經可以完成最基本的線程開啟,那麼在我們完成操作過程中用到了 java.lang.Thread 類,

API 中該類中定義了有關線程的一些方法,具體如下:

構造方法:

public Thread() : 配置設定一個新的線程對象。

public Thread(String name) : 配置設定一個指定名字的新的線程對象。

public Thread(Runnable target) : 配置設定一個帶有指定目标新的線程對象。

public Thread(Runnable target,String name) : 配置設定一個帶有指定目标新的線程對象并指定名字。

常用方法:

public String getName() : 擷取目前線程名稱。

public void start() : 導緻此線程開始執行 ; Java

虛拟機調用此線程的

run

方法。

public void run() : 此線程要執行的任務在此處定義代碼。

public static void sleep(long millis) : 使目前正在執行的線程以指定的毫秒數暫停(暫時停止執行)。

public static Thread currentThread() : 傳回對目前正在執行的線程對象的引用。

翻閱 API 後得知建立線程的方式總共有兩種,一種是繼承 Thread

類方式,一種是實作

Runnable

接口方式,方式一我

們上一天已經完成,接下來講解方式二實作的方式。

1.3 建立線程方式二

采用 java.lang.Runnable 也是非常常見的一種,我們隻需要重寫 run

方法即可。

步驟如下:

1. 定義 Runnable 接口的實作類,并重寫該接口的

run()

方法,該

run()

方法的方法體同樣是該線程的線程執行體。

2. 建立 Runnable 實作類的執行個體,并以此執行個體作為

Thread

target

來建立

Thread

對象,該

Thread

對象才是真正

的線程對象。

3. 調用線程對象的 start() 方法來啟動線程。

代碼如下:

【Java】什麼是線程?Thread和Runnable差別
【Java】什麼是線程?Thread和Runnable差別

通過實作 Runnable 接口,使得該類有了多線程類的特征。 run() 方法是多線程程式的一個執行目标。所有的多線程

代碼都在 run 方法裡面。 Thread 類實際上也是實作了

Runnable

接口的類。

在啟動的多線程的時候,需要先通過 Thread 類的構造方法 Thread(Runnable target) 構造出對象,然後調用

Thread

對象的 start() 方法來運作多線程代碼。

實際上所有的多線程代碼都是通過運作 Thread 的 start() 方法來運作的。是以,不管是繼承

Thread

類還是實作

Runnable 接口來實作多線程,最終還是通過 Thread 的對象的 API

來控制線程的,熟悉

Thread

類的

API

是進行多線程

程式設計的基礎。

tips:Runnable 對象僅僅作為 Thread 對象的 target

Runnable

實作類裡包含的

run()

方法僅作為線程執行體。

而實際的線程對象依然是 Thread 執行個體,隻是該 Thread 線程負責執行其

target

run()

方法。

1.4 Thread和Runnable的差別

如果一個類繼承 Thread ,則不适合資源共享。但是如果實作了 Runable 接口的話,則很容易的實作資源共享。

總結:

實作

Runnable

接口比繼承

Thread

類所具有的優勢:

1. 适合多個相同的程式代碼的線程去共享同一個資源。

2. 可以避免 java 中的單繼承的局限性。

3. 增加程式的健壯性,實作解耦操作,代碼可以被多個線程共享,代碼和線程獨立。

4. 線程池隻能放入實作 Runable 或 Callable

類線程,不能直接放入繼承

Thread

的類。

擴充:在 java 中,每次程式運作至少啟動 2 個線程。一個是

main

線程,一個是垃圾收集線程。因為每當使用

java 指令執行一個類的時候,實際上都會啟動一個 JVM ,每一個 JVM

其實在就是在作業系統中啟動了一個進

程。

1.5 匿名内部類方式實作線程的建立

使用線程的内匿名内部類方式,可以友善的實作每個線程執行不同的線程任務操作。

使用匿名内部類的方式實作 Runnable 接口,重新 Runnable 接口中的run方法: