Java中的ThreadPoolExecutor線程池原理細節(jié)解析
一、什么是ThreadPoolExecutor
ThreadPoolExecutor是一個線程池,最多可使用7個參數(shù)來控制線程池的生成。 使用線程池可以避免創(chuàng)建和銷毀線程的資源損耗,提高響應速度,并且可以管理線程池中線程的數(shù)量和狀態(tài)等等。 阿里巴巴手冊中也推薦使用該線程池,因為Executors創(chuàng)建緩存線程池時,最大線程數(shù)是Integer.MAX_VALUE,可能導致堆棧溢出。而且使用ThreadPoolExecutor創(chuàng)建線程池可以讓開發(fā)者更好理解線程池原理。
二、使用線程池的優(yōu)點
1.減少系統(tǒng)資源消耗
無須重復創(chuàng)建和銷毀線程,減少了線程創(chuàng)建和銷毀造成的資源消耗。
2.提高響應速度
創(chuàng)建好的線程會駐留在線程池中,無需創(chuàng)建新線程執(zhí)行任務,因而提高了響應速度。
3.提高了線程的可管理性。
線程池可以控制線程的數(shù)量,可以選擇拒絕策略,可以監(jiān)控和管理線程的狀態(tài),控制并發(fā)量等等。 這些都是自己創(chuàng)建線程難以做到的。
三、線程池原理
3.1 線程池的7個參數(shù)
1)corePoolSize 核心線程數(shù)
線程池常駐線程數(shù)量
2)maximumPoolSize 最大線程數(shù)
最大可存在的線程數(shù)量
3)keepAliveTime 非核心線程的存活時間
非核心線程空閑時,可以停留的時間
4)unit 存活時間的單位
非核心線程空閑時,可以停留的時間的單位
5)workQueue 阻塞隊列
線程都在使用中時,可以將任務保存在阻塞隊列中,可以設置隊列的長度。
6)threadFactory 線程創(chuàng)建工廠
可以選擇創(chuàng)建線程的工廠
7)handler 拒絕策略
當線程池無法存放更多任務時,處理這些過多的任務的策略
3.2 線程池執(zhí)行任務的流程
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    //判斷工作線程數(shù)是否小于核心線程數(shù)
    if (workerCountOf(c) < corePoolSize) {
    	//是,創(chuàng)建一個新線程
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //否,將任務嘗試添加到阻塞隊列中,如果隊列滿了則會添加失敗。
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        //判斷線程池狀態(tài)是否在運行中,不在運行中時,刪除該任務
        if (! isRunning(recheck) && remove(command))
        	//不在運行中時,執(zhí)行拒絕策略
            reject(command);
        //判斷工作線程數(shù)是否為0
        else if (workerCountOf(recheck) == 0)
        	//為0的場合,嘗試創(chuàng)建新線程
            addWorker(null, false);
    }
    //添加失敗的場合,嘗試創(chuàng)建一個新線程
    else if (!addWorker(command, false))
    	//如果添加失敗,執(zhí)行拒絕策略
        reject(command);
}- 當執(zhí)行一個任務時,首先會判斷工作線程數(shù)是否小于核心線程數(shù)。
- 如果小于核心線程數(shù),則創(chuàng)建一個新線程來執(zhí)行該任務。執(zhí)行完畢。
 
 - 如果大于核心線程數(shù),則嘗試將任務放入阻塞隊列中。
- 如果成功放入阻塞隊列,待有空閑的線程時,空閑線程會從阻塞隊列中獲取任務并執(zhí)行。執(zhí)行完畢。
 
 - 如果放入失敗,表示阻塞隊列已滿,此時會嘗試創(chuàng)建一個新線程來執(zhí)行該任務。
- 如果當前線程數(shù)小于最大線程數(shù),則會創(chuàng)建新線程來執(zhí)行該任務。執(zhí)行完畢。
 - 如果工作線程數(shù)等于最大線程數(shù),則不會創(chuàng)建新線程,嘗試創(chuàng)建失敗。此時會執(zhí)行拒絕策略。執(zhí)行完畢。
 
 
四、Executors提供的常用線程池
4.1 Executors.newFixedThreadPool
一個固定數(shù)量的線程池,可以通過傳入的參數(shù)int nThreads來控制線程池的線程數(shù)量。(核心線程數(shù)和最大線程數(shù)相同)
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }4.2 Executors.newSingleThreadExecutor
一個線程數(shù)只有1的線程池??梢员WC任務的順序執(zhí)行。
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }4.3 Executors.newCachedThreadPool
緩存線程池,新創(chuàng)建的線程會在該線程池中緩存60秒??梢蕴岣叨唐诋惒饺蝿盏男阅?。 注意,最大線程數(shù)是Integer.MAX_VALUE,高并發(fā)的場合下,可能會創(chuàng)建大量線程。
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }4.4 Executors.newScheduledThreadPool
定時任務線程池,使用該線程池可以定時執(zhí)行任務。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }到此這篇關于Java中的ThreadPoolExecutor線程池原理細節(jié)解析的文章就介紹到這了,更多相關ThreadPoolExecutor線程池原理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
 MyBatis-Flex實現(xiàn)多表聯(lián)查(自動映射)
我們可以輕松的使用 Mybaits-Flex 鏈接任何數(shù)據(jù)庫,本文主要介紹了MyBatis-Flex實現(xiàn)多表聯(lián)查(自動映射),具有一定的參考價值,感興趣的可以了解一下2024-06-06
 使用lombok的@Data會導致棧溢出StackOverflowError問題
這篇文章主要介紹了使用lombok的@Data會導致棧溢出StackOverflowError問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11
 Java中數(shù)據(jù)轉換及字符串的“+”操作方法
本文主要介紹了Java中的數(shù)據(jù)類型轉換,包括隱式轉換和強制轉換,隱式轉換通常用于將范圍較小的數(shù)據(jù)類型轉換為范圍較大的數(shù)據(jù)類型,而強制轉換則是將范圍較大的數(shù)據(jù)類型轉換為范圍較小的數(shù)據(jù)類型,本文介紹Java中數(shù)據(jù)轉換以及字符串的“+”操作,感興趣的朋友一起看看吧2024-10-10

