快速了解多線程的一些常見知識點
點擊上方“程序員大白”,選擇“星標”公眾號
重磅干貨,第一時間送達
在Java編程中,多線程是非常重要知識點. 關于Java線程有些不可不知的知識點需要牢記,下面就介紹了這些知識點.
1. 優(yōu)先級
每個Java線程都有對應的優(yōu)先級,高優(yōu)先級的線程比低優(yōu)先級的線程有更多的執(zhí)行機會。新創(chuàng)建的Java線程默認的優(yōu)先級是5, 最低是1,最高是10;
1 | /** |
Note:如果在一個線程中創(chuàng)建一個新的線程,新線程的默認優(yōu)先級和所在線程的優(yōu)先級保持一致。
2. daemon 或 非daemon
一個Java線程可以是daemon的也可以是非daemon的,JVM在啟動的時候啟動了main線程,該線程是非daemon;JVM在下面2的情況下會退回:
調(diào)用
Runtime.exit()方法所有非daemon的線程都結束了。
3. 創(chuàng)建線程的方式
有2種創(chuàng)建線程的方式,一種是繼承Thread類;一種是直接new一個Thread對象,并在構造函數(shù)中傳入一個Runnable對象。
繼承
1 | class PrimeThread extends Thread { |
4. 線程的狀態(tài)
JDK中關于線程狀態(tài)的定義:
new : 一個新創(chuàng)建的,沒有調(diào)用start方法的線程處于該狀態(tài);
RUNNABLE :可執(zhí)行的,在JVM中是處于執(zhí)行中,但是在等待其它的操作系統(tǒng)資源,如cpu資源;
BLOCKED :阻塞的,一個線程在進入(或再次進入)一個同步方法或同步塊時等待監(jiān)視器鎖時處于該狀態(tài)。
WAITING :等待,一個線程在調(diào)用了如下的方法時會處于等待狀態(tài):
1.Object.wait
2.Thread.join //正在主線程中調(diào)用一個一個線程的join方法,在主線程處于等待狀態(tài)
3.LockSupport#park()TIMED_WAITING 等待的,不過該等待狀態(tài)是有時間限制的。一個線程調(diào)用下面的方法會進入該狀態(tài):
1.Thread.sleep
2.Object.wait
3.Thread.join
4.LockSupport.parkNanos
5.LockSupport.parkUntilTERMINATED 終止,當一個線程執(zhí)行完成后處于該狀態(tài)
5. 線程的調(diào)度
理想的情況下,每個程序的線程都擁有一個專屬于自己的處理器;在計算機還不能擁有幾千,甚至幾百萬CPU處理器的情況下,多個線下需要共享僅有的cpu資源,如果分配線程執(zhí)行所需的cpu資源就需要線程調(diào)度器的調(diào)度了。在操作系統(tǒng)層面有自己的線程調(diào)度器,在JVM中也存在Java線程調(diào)度器。
在Java線程調(diào)度中有2點比較重要:
Java規(guī)范并沒有強制要求每個JVM按照特定的調(diào)度規(guī)則調(diào)用線程,或者必須包含一個線程調(diào)度器。線程調(diào)度的實現(xiàn)完全是依賴平臺的。
在編寫Java多線程代碼時,我們唯一需要考慮的是不要讓一個線程大量的占用cpu時間(eg.死循環(huán))。
大多數(shù)平臺上JVM的線程調(diào)度是依賴操作系統(tǒng)本身的線程調(diào)度器的,每個線下有不同的優(yōu)先級,在基于時間片的規(guī)則下,高優(yōu)先級的線程擁有更多的CPU執(zhí)行機會;相同優(yōu)先級的線程可以按照FIFO調(diào)度。
6. Runnable、Callable、Future 和 FutureTasek的區(qū)別
Java中存在Runnable、Callable、Future、FutureTask這幾個與線程相關的類或者接口,在Java中也是比較重要的幾個概念,我們通過下面的簡單示例來了解一下它們的作用與區(qū)別。
6.1 Runnable
Runnable 應該是這幾個類我們使用的最多的一個。JDK的文檔說明:如果一個類的實例想要通過一個線程來執(zhí)行,則該類應該實現(xiàn)Runnable接口。Runnable被設計用來對那些處于active狀態(tài)時會執(zhí)行代碼的對象提供一個統(tǒng)一的協(xié)議。例如Thread類就實現(xiàn)了Runnable接口。
1 | public interface Runnable { |
6.2 Callable
Callable 表示一個可以攜帶返回結果的任務。該接口的實現(xiàn)類需要一個沒有參數(shù)的call方法。Callable 和 Runnable類似,都是被設計用來被另外一個線程執(zhí)行的任務。但是Runnable不能返回一個結果,且不能拋出一個checked異常。
1 | public interface Callable<V> { |
6.3 Future
一個Futrue表示一個異步計算的結果。它提供了一系列方法,用來檢測計算是否完成,獲取計算結果,等待計算結果等。只能通過get方法獲取計算結果;如果計算沒有完成,在必要條件下,則get方法一直等待,直到任務完成。cancel方法用來取消任務。其它的方法都是用來測試計算是否完成,或是否取消。一旦計算完成后,就不可以被取消。如果你想使用Future,但并不需要返回一個結果,則可以使用Future>并返回null。
一個簡單的例子(JDK原文):
1 | class App { |
6.4 FutureTask
FutureTask 表示一個可以取消的異步計算任務。它實現(xiàn)了Runnable接口和Future接口。FutureTask 可以用來包裝Runnable和Callable對象。應該FutureTask實現(xiàn)了Runnable接口。同時可以通過被提交到Executor去執(zhí)行。
1 | public FutureTask(Callable |
可以看到,Runnable注入會被Executors.callable()函數(shù)轉換為Callable類型,即FutureTask最終都是執(zhí)行Callable類型的任務。該適配函數(shù)的實現(xiàn)如下 :
1 | public static |
RunnableAdapter適配器
1 | /** |
7. 總結
由于FutureTask實現(xiàn)了Runnable,因此它既可以通過Thread包裝來直接執(zhí)行,也可以提交給ExecuteService來執(zhí)行。
并且還可以直接通過get()函數(shù)獲取執(zhí)行結果,該函數(shù)會阻塞,直到結果返回。因此FutureTask既是Future、
Runnable,又是包裝了Callable(如果是Runnable最終也會被轉換為Callable ), 它是這兩者的合體。
source: //leokongwq.github.io/2016/10/16/java-runnable-callable-future.html
推薦閱讀
國產(chǎn)小眾瀏覽器因屏蔽視頻廣告,被索賠100萬(后續(xù))
年輕人“不講武德”:因看黃片上癮,把網(wǎng)站和786名女主播起訴了
關于程序員大白
程序員大白是一群哈工大,東北大學,西湖大學和上海交通大學的碩士博士運營維護的號,大家樂于分享高質(zhì)量文章,喜歡總結知識,歡迎關注[程序員大白],大家一起學習進步!


