首頁>技術>

執行緒有三種建立方式:

A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.

Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.

When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:

- The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.

- All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread. An instance of the subclass can then be allocated and started.

The other way to create a thread is to declare a class that implements the Runnable interface. That class then implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started.

執行緒(Java中Thread類)是程式執行的一個執行緒。Java虛擬機器允許一個應用程式併發地執行多個執行緒。

每個執行緒有一個優先順序。高優先順序的執行緒會比低優先順序的執行緒優先執行。每個執行緒可以被設定或不設定為守護執行緒。當某個執行緒的程式碼中建立了一個新的執行緒物件,那麼新的執行緒物件擁有和建立它的執行緒物件相同的優先順序。建立新執行緒的執行緒是守護執行緒的時候,新執行緒才會是守護執行緒。

當一個Java虛擬機器啟動的時候,通常只有一個非守護執行緒(這個非守護執行緒會呼叫指定類的main方法)。Java虛擬機器會一直執行執行緒直到以下情況之一出現:

- Runtime類的exit方法被呼叫並且安全管理器執行退出。

- 所有的非守護執行緒執行結束,要麼是run方法正常結束,要麼是run方法異常退出。

有兩種方法可以建立一個執行緒。一個是宣告一個Thread類的子類,該子類要重寫run方法,然後該子類的例項物件便可以被分配和啟動了。

另一個建立執行緒的方法是實現run方法,並且實現run方法。該類的例項物件可以被分配,將它作為引數傳給Thread物件建立的時候,便可以啟動了。

官方文件提到了執行緒優先順序和守護執行緒的概念,這個我們先不管,我們先關注如何建立執行緒。這裡它提到了兩種方式,繼承Thread類和實現Runnable介面。我們來看下這兩個方法如何實現。

繼承Thread類

繼承Thread類方法分為3步:

繼承Thread實現run方法建立該類的執行緒物件呼叫start方法啟動執行緒

來看程式碼實現:

繼承Thread實現run方法

建立該類的執行緒物件

呼叫start方法啟動執行緒

SubThread類重寫的run方法幹了一件事就是列印0~9,並且每列印一個數字,休眠1s。

程式執行效果如下:

task1和task2分別表示了執行緒1和執行緒2,可以看到執行緒1和執行緒2交替在執行。

在這裡要特別注意的是run方法和start 方法。run方法是我們重寫的方法,而start方法是我們呼叫啟動執行緒執行的方法,這兩個千萬不要搞混了。執行緒建立好不會立即執行,需要我們手動呼叫讓它開始執行,run方法是我們告訴計算機要執行什麼事情,start則是計算機可以開始執行了。

實現Runnable介面

實現Runnable介面方法分為4步:

實現Runnable介面並實現run方法建立該類物件將上述物件作為引數傳給Thread的構造方法建立Thread物件呼叫start方法啟動執行緒

相比繼承Thread類的方法主要是多了一步傳遞物件引數建立Thread物件的步驟,而實現run方法和呼叫start方法是不變的,注意這裡也不要搞混run方法和start方法,下面來看下程式碼實現:

實現Runnable介面並實現run方法

建立該類物件

將上述物件作為引數傳給Thread的構造方法建立Thread物件

呼叫start方法啟動執行緒

RunnableImpl類實現的run方法和SubThread類功能一樣,執行結果如下:

task1和task2分別表示了執行緒1和執行緒2,可以看到執行緒1和執行緒2交替在執行,基本和繼承Thread方法保持一致。

實現Callable介面

前面兩種方法繼承Thread類和實現Runnable介面有一個很明顯的缺陷就是,在執行完任務之後無法獲取執行結果。如果要獲取執行結果,需要定義變數其他執行緒再來獲取這個共享變數,比較麻煩。在Java1.5以後,提供了Callable可以獲取到執行緒執行結果。

實現Callable介面方法分為6步:

繼承Callable介面實現call方法建立ExecutorService物件建立Callable實現類的物件呼叫submit方法提交執行獲取結果執行緒執行結果關閉ExecutorService

來看程式碼實現:

繼承Callable介面實現call方法

建立ExecutorService物件

建立Callable實現類的物件

呼叫submit方法提交執行

獲取結果執行緒執行結果

關閉ExecutorService

CallableImpl類實現的run方法和SubThread類功能一樣,執行結果如下:

因為Callable有返回值,所以最後列印了輸出結果,如下:

建立執行緒方式小結

綜合來看,建立執行緒方式只有兩種,一種是實現Runnable介面,一種是實現Callable介面,因為Thread類實際上也是實現了Runnable介面:

Thread實現Runnable介面

在日常程式碼開發中,我們也是使用的實現Runnable介面比較多,因為繼承Thread類會有單繼承問題。所以我們只要記住RunnableCallable介面就可以了,記住實現兩個方法:runcall

而從步驟上來講,核心的有三步:

實現介面(Runnable或Callable)建立執行緒(Thread類或ExecutorService執行緒池)啟動執行(start或submit)

本次學習結束,所有原始碼可見GitHub(https://github.com/Yohohaha/concurrency-learning),下次分享繼續~

16
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 邊學邊記:RPC框架呼叫過程