juc - 線程池之七大參數(shù)介紹和正確的構(gòu)造線程池

線程池之七大參數(shù)

我們知道,線程池的核心類是 ThreadPoolExecutor,構(gòu)造一個ThreadPoolExecutor需要7個參數(shù)!


image.png
int corePoolSize

線程池中的常駐核心線程數(shù)

int maximumPoolSize

線程池中能夠容納同時執(zhí)行的最大線程數(shù),此值必須大于等于1

long keepAliveTime

多余的空閑線程的存活時間。當(dāng)前池中的線程數(shù)量超過corePoolSize時,多余線程會被銷毀到只剩下corePoolSize個線程為至

TimeUnit unit

keepAliveTime的單位

BlockingQueue<Runnable> workQueue

任務(wù)隊(duì)列,被提交但未被執(zhí)行的任務(wù)。由阻塞隊(duì)列實(shí)現(xiàn),關(guān)于阻塞隊(duì)列我這篇文章有講解 http://www.itdecent.cn/p/862c93ab3203

ThreadFactory threadFactory

表示生產(chǎn)線程池中工作線程的工廠。用于創(chuàng)建線程,一般默認(rèn)即可

RejectedExecutionHandler handler

拒絕策略,表示當(dāng)隊(duì)列滿了,并且工作線程大于等于線程池的最大線程數(shù)(maximumPoolSize)時如何來拒絕請求執(zhí)行的runnable餓策略。
我的這篇文章有詳細(xì)的講解拒絕策略
http://www.itdecent.cn/p/bf6fabb7b459

實(shí)際上我們應(yīng)該如何使用線程池?

不允許直接使用jdk自帶的三種線程池

Executors.newCachedThreadPool();
Executors.newFixedThreadPool(5);
Executors.newSingleThreadExecutor();

工作中請使用自定義的寫法:直接使用ThreadPoolExecutor類帶上7個參數(shù)構(gòu)造線程池!因?yàn)榭赡軐?dǎo)致oom異常,所謂oom異常就是 java.lang.OutOfMemoryError:Java heap space

image.png

實(shí)際上請使用ThreadPoolExecutor類帶上7個參數(shù)來構(gòu)造線程池
  • 注意指定隊(duì)列的長度,我這里是new LinkedBlockingQueue<>(3)。如果不指定3,則隊(duì)列長度為Integer.MAX_VALUE,可能因?yàn)槿蝿?wù)的積累導(dǎo)致oom。

    image.png

  • maximumPoolSize在cpu密級型項(xiàng)目中請配置成 cup核心數(shù)+1==>Runtime.getRuntime().availableProcessors()+1
    maximumPoolSize在io密級型項(xiàng)目中請配置成 cpu核心數(shù)/阻塞系數(shù)

參數(shù)調(diào)整試驗(yàn)

使用如下代碼來構(gòu)造線程池。2個核心線程,5個最大數(shù)量,3個等待隊(duì)列席位。

        ExecutorService executorService =
                new ThreadPoolExecutor(
                        2,
                        5,
                        2, TimeUnit.SECONDS,
                        new LinkedBlockingQueue<>(3),
                        Executors.defaultThreadFactory(),
                        new ThreadPoolExecutor.AbortPolicy());
實(shí)驗(yàn)一,任務(wù)數(shù)量為6
import java.util.concurrent.*;

public class Test {

    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(2, 5, 2, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        try {
            for (int i = 1; i <= 6; i++) {
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName() + " 辦理業(yè)務(wù)");
                    }
                });
            }
        } finally {
            executorService.shutdown();
        }

    }
}

這里有6個任務(wù)。所以線程池的核心線程、等待隊(duì)列都被用完。還剩下1個任務(wù)(6-2-3=1),需要創(chuàng)建線程來執(zhí)行。所以執(zhí)行結(jié)果中打印了pool-1-thread-3,該線程即是線程池臨時創(chuàng)建出來的線程!


image.png
實(shí)驗(yàn)二,任務(wù)數(shù)量為9
package com.springboot.study.demo1;
import java.util.concurrent.*;
class Test1 {

    public static void main(String[] args) {
        //2個核心線程 等待數(shù)量席位3個  最大線程數(shù)5個,那么最大容納任務(wù)是8個
        ExecutorService executorService = new ThreadPoolExecutor(2, 5, 2, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        try {
            //提交9次任務(wù),超出的1個任務(wù)會被應(yīng)用拒絕策略
            for (int i = 1; i <= 9; i++) {
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName() + " 辦理業(yè)務(wù)");
                    }
                });
            }
        } finally {
            executorService.shutdown();
        }
    }
}

執(zhí)行結(jié)果:抱錯。此時任務(wù)數(shù)量9超過線程池可接受的最大任務(wù)數(shù)8(maximumPoolSize 3 +workQueue的容量5)

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task Test$1@42110406 rejected from java.util.concurrent.ThreadPoolExecutor@531d72ca[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0]

創(chuàng)建自定義線程工廠為線程池中線程命名

創(chuàng)建線程池時使用自定義的線程工廠,這樣可以為該線程池內(nèi)的線程改名

package io.renren;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class UserThreadFactory implements ThreadFactory {
    private final String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);
    // 定義線程組名稱,在 jstack 問題排查時,非常有幫助
     public UserThreadFactory(String whatFeaturOfGroup) {
        namePrefix = "來自 UserThreadFactory 線程工廠的 " + whatFeaturOfGroup + "-線程-";
    }
    @Override
    public Thread newThread(Runnable task) {
        String name = namePrefix + nextId.getAndIncrement();
        Thread thread = new Thread(null, task, name, 0);
        System.out.println(thread.getName());
        return thread;
    }
}

class TestFa{

    public static void main(String[] args) {

        UserThreadFactory userThreadFactory = new UserThreadFactory(" 用戶 ");

        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(
                        2,
                        5,
                        2, TimeUnit.SECONDS,
                        new LinkedBlockingQueue<>(3),
                        userThreadFactory ,
                        new ThreadPoolExecutor.AbortPolicy());

        for (int i = 0; i <8 ; i++) {
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }

        threadPoolExecutor.shutdown();


    }

}
ThreadFactory 匿名
        ThreadFactory threadFactory = new ThreadFactory() {
            AtomicInteger nextId = new AtomicInteger(1);
            @Override
            public Thread newThread(Runnable task) {
                Thread thread = new Thread(null, task, "測試redis分布式鎖線程" + nextId.getAndIncrement(), 0);
                return thread;
            }
        };

        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(2,
                        5,
                        3,
                        TimeUnit.MINUTES,
                        new ArrayBlockingQueue<>(5),
                        threadFactory,
                        new ThreadPoolExecutor.AbortPolicy()
                );

        for (int i = 0; i <10 ; i++) {
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {

                    System.out.println(Thread.currentThread().getName());

                }
            });
        }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容