Java線程池源碼及原理

来源:https://www.cnblogs.com/powercto/archive/2019/07/14/11182754.html
-Advertisement-
Play Games

Java線程池的原理,主要參數的作用。ThreadPoolExecutor內部有重要的成員變數ctl,類型是AtomicInteger,低29位表示線程池中線程數,通過高3位表示線程池的運行狀態。addWorker的邏輯,runWorker的邏輯 ...


目錄

1 說明

下麵如果有貼出源碼,對應的源碼是JDK8
主要的源碼類
java.util.concurrent.ThreadPoolExecutor、
java.util.concurrent.ThreadPoolExecutor.Worker
java.util.concurrent.AbstractExecutorService

1.1類繼承圖

2 線程池的狀態

3 源碼分析

3.1完整的線程池構造方法

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

3.2 ctl

內部有重要的成員變數ctl,類型是AtomicInteger,低29位表示線程池中線程數,通過高3位表示線程池的運行狀態
COUNT_BITS的值是29
1、RUNNING:-1 << COUNT_BITS,即高3位為111,該狀態的線程池會接收新任務;
2、SHUTDOWN: 0 << COUNT_BITS,即高3位為000,該狀態的線程池不會接收新任務;
3、STOP : 1 << COUNT_BITS,即高3位為001;
4、TIDYING : 2 << COUNT_BITS,即高3位為010, 所有的任務都已經終止;
5、TERMINATED: 3 << COUNT_BITS,即高3位為011, terminated()方法已經執行完成

3.3 任務的執行

execute --> addWorker --> Thread.start --> (Thread.run) --> runTask --> getTask

3.3.1 execute(Runnable command)

大致分三個步驟
1、當前運行的線程數量是否小於corePoolSize,直接嘗試addWorker()
2、往阻塞隊列裡面放入Runnable任務
3、如果隊列已經滿了,直接嘗試addWorker()

3.3.2 addWorker(Runnable firstTask, boolean core)

1、前置判斷線程池的狀態
2、通過CAS操作讓ctl加1,表示運行線程數增加1個
3、構造一個Worker w,這裡要特別註意構造方法裡面的這行代碼,this.thread = getThreadFactory().newThread(this),可以看到構造方法內,有一個Thread對象,其使用了ThreadFactory構造了一個新的線程,並且線程的runable是worker本身。
4、執行w.thread.start(),也就是說,當該線程被運行時,Worker中的run方法會被執行

3.3.3 runWorker(Worker w)

通過迴圈調用getTask()獲取要執行的任務task
beforeExecute
task.run()
afterExecute

3.3.4 getTask()

直接貼源碼了

private Runnable getTask() {
    boolean timedOut = false; // 是否最後的 poll() 超時了?
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;    // worker是否需要被淘汰

        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            // 這裡會讓線程的數量記錄減,後面的return null,會導致runWorker沒有獲取到數據而讓run()方法走到盡頭,最終當前線程結束
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            // 如果需要回收一部分線程,那麼超時時間keepAliveTime後拿不到就數據就繼續迴圈調用,就可以在下一次迴圈的時候進行線程結束回收了;否則一直阻塞下去
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

4 任務執行,帶返回值的

直接貼源碼了

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

代碼比較簡單,把任務封裝成一個既實現Runnable, 也實現Future的介面,這個時候就可以調用execute()進行實現了

5 參考資料

https://blog.csdn.net/programmer_at/article/details/79799267
https://blog.csdn.net/liuzhixiong_521/article/details/87856121


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • HTML代碼: js代碼: ...
  • 可以使用 window.location 獲取當前頁面url。以下是一些簡單應用。 ...
  • html代碼: js代碼: ...
  • 史上最全的,web前端零基礎,系統學習路線圖!學好web前端,前途寬廣!如今隨著“互聯網+”上升到國家戰略,軟體行業與國民經濟關係密,幾乎絕大多數行業的發展都會促進軟體行業的發展。 ...
  • 編譯原理課程設計詞法分析任務書 5)參考文獻: (1)張素琴,呂映芝. 編譯原理[M]., 清華大學出版社 (2)蔣立源、康慕寧等,編譯原理(第2版)[M],西安:西北工業大學出版社 6)課程設計進度安排 1.準備階段(4學時):選擇設計題目、瞭解設計目的要求、查閱相關資料 2.程式模塊設計分析階段 ...
  • 舉個慄子 問題描述 要求有一個簡歷類,必須要有姓名,可以設置性別和年齡,可以設置工作經歷,最終需要三份簡歷。 簡單實現 簡歷類 測試 測試結果 存在的問題 跟手寫簡歷沒有差別,三份簡歷需要三份實例化,如果客戶需要二十份簡歷,那就得實例化二十次。 原型模式 定義 用原型實例指定創建對象的種類,並且通過 ...
  • SpringCloud系列教程 | 第十三篇:Spring Cloud Gateway服務化和過濾器 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如無特殊說明,本系列教程全採用以上版本 上一篇文章服務網關 Spring Cloud Gat ...
  • 最近這破事賊多,都沒有什麼時間寫寫博客,都好久都沒有更新博客了!不過平常看jdk源碼的時候有很大的感觸,就是基礎真的很重要,那什麼是基礎呢?除了java的基本語法之外,最基礎的莫過於原碼,反碼和補碼了以及基本的運算了! 又是我是編程半路出家,最開始的時候學過一點這些東西,當時只是感覺,擦!我是寫代碼 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...