線程和線程池

多線程編程是業務開發中要用到的一項技術,盡管面臨著一些挑戰,但多線程開發也有著很多優點,例如資源利用率更好,程序設計在某些情況下更簡單,程序響應更快等等。接下來主要說一下線程的幾種創建方式以及線程池的應用。

1通過繼承Thread的方式來創建線程


2通過實現Runnable接口來創建線程


這兩種方式本質上其實是一樣的,都是通過run()方法,深挖源碼的話,第一種方式中Thread其實也是實現了Runnable接口,然后重寫run()方法。然而這兩種方式有一個不足,就是run()方法里并不能返回一個結果和拋出異常,所以就有了第三種創建線程的方式,通過Callable接口,并用FutureTask來接收返回的對象。

3通過Callable接口,并用FutureTask來接收返回的對象


和Runnable接口不一樣,Callable接口提供了一個call()方法作為線程執行體,call()方法比run()方法功能要強大。call()方法可以有返回值,call()方法可以聲明拋出異常

Java5提供了Future接口來代表Callable接口里call()方法的返回值,并且為Future接口提供了一個實現類FutureTask,這個實現類既實現了Future接口,還實現了Runnable接口,因此可以作為Thread類的target。在Future接口里定義了幾個公共方法來控制它關聯的Callable任務。

接下來說線程池,線程池是管理線程的地方,在一個項目中,我們知道需要多次的創建線程和銷毀線程,然而創建和銷毀是及其耗費內存資源的,所以就有了線程池的需要,來幫我們管理調度線程,省下了很多的內存資源。

我們應該如何創建一個線程池那?Java中已經提供了創建線程池的一個類:Executor

而我們創建時,一般使用它的子類:ThreadPoolExecutor。但是從ThreadPoolExecutor到Executor并不是簡單的實現或繼承關系,兩者中間有好多中間類。下面是各類之間的層級關系調用實現類圖


線程池類圖

我把這幾個類用黑色線條畫了起來,發現我們需要的ThreadPoolExecutor首先繼承了抽象類AbstractExecutorService,然后AbstractExecutorService實現了ExecutorService接口,最ExecutorService接口又實現了Executor接口。

我們再來看一下ThreadPoolExecutor構造函數的參數


我們可以看出,線程池中的corePoolSize就是線程池中的核心線程數量,這幾個核心線程,只是在沒有用的時候,也不會被回收,maximumPoolSize就是線程池中可以容納的最大線程的數量,而keepAliveTime,就是線程池中除了核心線程之外的其他的最長可以保留的時間,因為在線程池中,除了核心線程即使在無任務的情況下也不能被清除,其余的都是有存活時間的,意思就是非核心線程可以保留的最長的空閑時間,而util,就是計算這個時間的一個單位,workQueue,就是等待隊列,任務可以儲存在任務隊列中等待被執行,執行的是FIFIO原則(先進先出)。threadFactory,就是創建線程的線程工廠,最后一個handler,是一種拒絕策略,我們可以在任務滿了之后,拒絕執行某些任務,具體的拒絕策略如下:

ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。

ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。

ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)

ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務

再來看線程池的執行流程


線程池的執行流程

我們可以看出,任務進來時,首先執行判斷,判斷核心線程是否處于空閑狀態,如果不是,核心線程就先就執行任務,如果核心線程已滿,則判斷任務隊列是否有地方存放該任務,若果有,就將任務保存在任務隊列中,等待執行,如果滿了,在判斷最大可容納的線程數,如果沒有超出這個數量,就開創非核心線程執行任務,如果超出了,就調用handler實現拒絕策略。

下面一段測試代碼來說明這個線程池執行的流程


最后運行結果與執行流程是一樣的,都是先判斷核心線程,當核心線程最大后,在判斷隊列,當隊列也滿后,在進入非核心線程。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android中的線程 線程,在Android中是非常重要的,主線程處理UI界面,子線程處理耗時操作。如果在主線程...
    shenhuniurou閱讀 812評論 0 3
  • 不同形式的線程雖然都是線程,但是它們仍然具有不同的特性和實用場景: AsyncTask封裝了線程池和Handler...
    胡二囧閱讀 1,146評論 0 4
  • 一.Java中的ThreadPoolExecutor類 java.uitl.concurrent.ThreadPo...
    誰在烽煙彼岸閱讀 666評論 0 0
  • 導語 在Android系統,線程主要分為主線程和子線程,主線程處理和界面相關的事情,而子線程一般用于執行耗時操作。...
    一個有故事的程序員閱讀 614評論 0 3
  • 1 你的樣子跟別人不同。 每次點開運動的app,總是看到圈內的人都在曬各種健身后的照片或撩腹部的照片。不記得聽誰說...
    聽風想雨閱讀 321評論 5 1