欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java之線程池使用與原理全面解析

 更新時間:2024年03月27日 09:28:21   作者:NingKangMing  
這篇文章主要介紹了Java之線程池使用與原理全面解析,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

為什么要使用線程池?

JDK1.5后JUC包添加了線程池相關(guān)接口,在Java誕生之初并沒有線程池這個概念。

剛開始Java程序都是自行創(chuàng)建線程去處理任務(wù)。隨著應(yīng)用使用的線程越來越多,JDK開發(fā)者們發(fā)現(xiàn)有必要使用一個統(tǒng)一的類來管理這些線程,從而有效提高線程的執(zhí)行效率,減少創(chuàng)建、銷毀線程的開銷。

大量線程的創(chuàng)建、銷毀是非常消耗資源的。創(chuàng)建線程需要消耗一定的內(nèi)存、CPU資源,大量的線程也會導(dǎo)致大量的線程上下文切換,上下文切換代碼也是相當(dāng)大的,過多的線程導(dǎo)致頻繁切換更是可能使系統(tǒng)性能急速下降。

另外操作系統(tǒng)對每個進程能創(chuàng)建的線程數(shù)也是有限制的,不可能無限創(chuàng)建。但是大量任務(wù)也不可能只在主線程處理吧,這樣也太慢了。

比如下面的例子,創(chuàng)建上萬的線程,每個線程打印一下線程名字,觀察一下任務(wù)管理器,CPU直接用完。

這只是簡單的任務(wù),要是復(fù)雜長時間的任務(wù),整個操作系統(tǒng)可能都會受到影響(CPU利用率長時間下不來,影響其他程序)

public class BadMultiThreadTest {
 
    public static void main(String[] args) {
        Runnable r = () -> {
            System.out.println("ThreadName-" + Thread.currentThread().getName());
        };
        //過多創(chuàng)建線程導(dǎo)致系統(tǒng)資源消耗嚴(yán)重
        for (int i = 0; i < 10000; i++) {
            Thread thread = new Thread(r);
            thread.start();
        }
    }
}

線程池就是為了解決上述問題出現(xiàn)的,解決問題的思路很清晰,就是創(chuàng)建好一定數(shù)量的線程,有任務(wù)來了就用這些線程來執(zhí)行任務(wù),任務(wù)過多把池里面的線程都占用了就放隊列排隊等候其他任務(wù)執(zhí)行,一旦有空閑線程就可以從隊列里面取出任務(wù)并執(zhí)行。

有了可控的線程池,系統(tǒng)就不會處于一種可能隨時被大量并發(fā)導(dǎo)致線程大量創(chuàng)建,最終壓跨系統(tǒng)的危險中。

如何使用線程池?

使用線程池去改造上面的例子:

public class MultiThreadPoolTest {
 
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10000; i++) {
            executorService.execute(() -> {
                System.out.println("ThreadName-" + Thread.currentThread().getName());
            });
        }
    }
}

這次再觀察任務(wù)管理器,這次CPU占用不會說飆長,而是相對平穩(wěn)。打印的線程名稱就是在ThreadName-pool-1-thread-1到ThreadName-pool-1-thread-10之間變化,說明這一萬個任務(wù)都是這10個線程處理的。 

線程池的參數(shù)含義

上面的例子簡單的使用了Excutors工具類來創(chuàng)建了一個固定線程數(shù)的線程池。

這個工具類還可以創(chuàng)建單線程線程池、可緩存線程池、定時執(zhí)行任務(wù)的線程池等。

這些線程池的創(chuàng)建事實上都是在創(chuàng)建一個ThreadPoolExecutor實例,只是通過傳遞不同參數(shù),實現(xiàn)不同的線程池效果而已。

如果我們把里面的參數(shù)都搞明白,我們就可以根據(jù)實際需求去自定義線程池,實際開發(fā)中,我們都應(yīng)該使用自定義的線程池去處理相關(guān)業(yè)務(wù),這樣能最大提高線程池使用效率,提高系統(tǒng)性能。當(dāng)然,這還得靠我們對業(yè)務(wù)的理解,從而定義出合理的線程池。

通過下面這句代碼,跟蹤源碼

Executors.newFixedThreadPool(10);

最終調(diào)用的函數(shù)如下,它包含了線程池的所有參數(shù)注釋:

    /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

下面簡單總結(jié)一下參數(shù)的含義:

參數(shù)名稱含義
corePoolSize核心線程數(shù)
maximumPoolSize最大線程數(shù)
keepAliveTime+時間單位空閑線程存活時間
workQueue任務(wù)隊列
threadFactory創(chuàng)建線程的工廠類
handler被拒絕任務(wù)處理器

線程池處理任務(wù)的流程

看一下下面的流程圖就能清晰知道任務(wù)從被提交再到被線程池中線程執(zhí)行的流程了。

如上流程圖,任務(wù)被提交后,線程池會檢查核心線程數(shù)是否滿了,如果不是,則會創(chuàng)建一條核心線程以執(zhí)行該任務(wù)。

如果滿了,則把任務(wù)放到阻塞隊列中,等待有空閑的核心線程來執(zhí)行任務(wù)。阻塞隊列如果也滿了,則需要檢查最大核心線程數(shù)是否滿了,如果沒滿,創(chuàng)建非核心線程以執(zhí)行任務(wù),如果滿了,表示線程池再也沒能力去處理該任務(wù)了,則需要拒絕策略做處理。

注意到構(gòu)建線程池的參數(shù)中有keepAliveTime+時間單位這兩個參數(shù),這兩個參數(shù)正是用于回收非核心線程用的,當(dāng)非核心線程沒任務(wù)了,空閑時間達到keepAliveTime配置的值后將會被線程池銷毀以回收一些系統(tǒng)資源。

使用線程池的優(yōu)點

  • 根據(jù)上面可以簡略總結(jié)出使用線程池的幾點優(yōu)點:
  • 解決線程創(chuàng)建、銷毀等生命周期系統(tǒng)消耗過大問題。因為線程池中的線程一旦創(chuàng)建過,核心線程是會一直駐留在池中待用的,這樣任務(wù)來了后,直接可以執(zhí)行,消除了創(chuàng)建線程的系統(tǒng)開銷。系統(tǒng)響應(yīng)更及時,使用更絲滑。
  • 線程池使得系統(tǒng)可控性更強。它避免了系統(tǒng)資源使用不當(dāng)導(dǎo)致系統(tǒng)崩潰,能更合理的使用CPU和內(nèi)存資源。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于java實現(xiàn)websocket代碼示例

    基于java實現(xiàn)websocket代碼示例

    這篇文章主要介紹了基于java實現(xiàn)websocket代碼示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-12-12
  • Spring Boot集成Thymeleaf模板引擎的完整步驟

    Spring Boot集成Thymeleaf模板引擎的完整步驟

    這篇文章主要給大家介紹了關(guān)于Spring Boot集成Thymeleaf模板引擎的完整步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • mybatis之批量添加問題

    mybatis之批量添加問題

    這篇文章主要介紹了mybatis之批量添加問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • SpringMvc MultipartFile實現(xiàn)圖片文件上傳示例

    SpringMvc MultipartFile實現(xiàn)圖片文件上傳示例

    本篇文章主要介紹了SpringMvc MultipartFile實現(xiàn)圖片文件上傳示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • java 8 lambda表達式list操作分組、過濾、求和、最值、排序、去重代碼詳解

    java 8 lambda表達式list操作分組、過濾、求和、最值、排序、去重代碼詳解

    java8的lambda表達式提供了一些方便list操作的方法,主要涵蓋分組、過濾、求和、最值、排序、去重,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-01-01
  • Spring?Boot如何監(jiān)控SQL運行情況?

    Spring?Boot如何監(jiān)控SQL運行情況?

    Druid是Java語言中最好的數(shù)據(jù)庫連接池,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot如何監(jiān)控SQL運行情況的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • Java進階教程之異常處理

    Java進階教程之異常處理

    這篇文章主要介紹了Java進階教程之異常處理,本文講解了JAVA的異常處理機制、異常的類型、拋出異常、自定義異常等內(nèi)容,需要的朋友可以參考下
    2014-09-09
  • 基于Freemarker和xml實現(xiàn)Java導(dǎo)出word

    基于Freemarker和xml實現(xiàn)Java導(dǎo)出word

    這篇文章主要介紹了基于Freemarker和xml實現(xiàn)Java導(dǎo)出word,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • Spring Boot如何通過CORS處理跨域問題

    Spring Boot如何通過CORS處理跨域問題

    這篇文章主要介紹了Spring Boot如何通過CORS處理跨域問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • Java中this的用法實例總結(jié)

    Java中this的用法實例總結(jié)

    JAVA中的this是一個非常重要的模塊,在編程中有非常重要的地位,擅長用this的人常常可以使程序更加簡潔和方便,下面這篇文章主要給大家介紹了關(guān)于Java中this用法的相關(guān)資料,需要的朋友可以參考下
    2022-08-08

最新評論