溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

線程池主要參數(shù)有哪些

發(fā)布時間:2021-10-20 10:27:55 來源:億速云 閱讀:132 作者:iii 欄目:編程語言

這篇文章主要介紹“線程池主要參數(shù)有哪些”,在日常操作中,相信很多人在線程池主要參數(shù)有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”線程池主要參數(shù)有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

(一)什么是線程池

線程(thread)是操作系統(tǒng)能夠進行運算調(diào)度的最小單位。它被包含在進程之中,是進程中的實際運作單位,我們的程序最終都是由線程進行運作。在Java中,創(chuàng)建和銷毀線程的動作是很消耗資源的,因此就出現(xiàn)了所謂“池化資源”技術(shù)。

線程池是池化資源技術(shù)的一個應(yīng)用,所謂線程池,顧名思義就是預(yù)先按某個規(guī)定創(chuàng)建若干個可執(zhí)行線程放入一個容器中(線程池),需要使用的時候從線程池中去取,用完之后不銷毀而是放回去,從而減少了線程創(chuàng)建和銷毀的次數(shù),達到節(jié)約資源的目的。

(二)為什么要使用線程池

2.1 降低資源消耗

前面已經(jīng)講到線程池的出現(xiàn)減少了線程創(chuàng)建和銷毀的次數(shù),每個線程都可以被重復(fù)利用,可執(zhí)行多個任務(wù)。

2.2 提高系統(tǒng)的響應(yīng)速度

每當(dāng)有任務(wù)到來時,直接復(fù)用線程池中的線程,而不需要等待新線程的創(chuàng)建,這個動作可以帶來響應(yīng)速度的提升

2.3 防止過多的線程搞壞系統(tǒng)

可以根據(jù)系統(tǒng)的承受能力,調(diào)整線程池中的工作線程的數(shù)量,防止因為線程過多服務(wù)器變慢或死機。java一個線程默認占用空間為1M,可以想象一旦手動創(chuàng)建線程過多極有可能導(dǎo)致內(nèi)存溢出。

(三)線程池主要參數(shù)

我們可以用Executors類來創(chuàng)建一些常用的線程池,但是像阿里是禁止直接通過Executors類直接創(chuàng)建線程池的,具體的原因稍后再談。

在了解Executors類所提供的幾個線程池前,我們首先來了解一下 ThreadPoolExecutor的主要參數(shù),ThreadPoolExecutor是創(chuàng)建線程池的類,我們選取參數(shù)最多的構(gòu)造方法來看一下:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
名稱類型含義
corePoolSizeint核心線程池的大小
maximumPoolSizeint最大線程池大小
keepAliveTimelong線程最大空閑時間
unitTimeUnit時間單位
workQueueBlockingQueue<Runnable>線程等待隊列
threadFactoryThreadFactory線程創(chuàng)建工程
handlerRejectedExecutionHandler拒絕策略

3.1 corePoolSize

當(dāng)向線程池提交一個任務(wù)時,如果線程池中已創(chuàng)建的線程數(shù)量小于corePoolSIze,即便存在空閑線程,也會創(chuàng)建一個新線程來執(zhí)行任務(wù),直到創(chuàng)建的線程數(shù)大于或等于corePoolSIze。

3.2 maximumPoolSize

線程池所允許的最大線程個數(shù),當(dāng)隊列滿了且已經(jīng)創(chuàng)建的線程數(shù)小于maximumPoolSize時,會創(chuàng)建新的線程執(zhí)行任務(wù)。

3.3 keepAliveTime

當(dāng)線程中的線程數(shù)大于corePoolSIze時,如果線程空閑時間大于keepAliveTime,該線程就會被銷毀。

3.4 unit

keepAliveTime的時間單位

3.5 workQueue

用于保存等待執(zhí)行任務(wù)的隊列

3.6 threadFactory

用于創(chuàng)建新線程。threadFactory創(chuàng)建的線程也是采用new Thread()方式,threadFactory創(chuàng)建的線程名都具有統(tǒng)一的風(fēng)格:pool-m-thread-n

3.7 handler

拒絕策略,當(dāng)線程池和隊列滿了之后,再加入新線程后會執(zhí)行此策略。 下面是四種線程池的拒絕策略:

AbortPolicy:中斷任務(wù)并拋出異常

DiscardPolicy:中段任務(wù)但是不拋出異常

DiscardOldestPolicy:丟棄隊列中最老的任務(wù),然后嘗試提交新任務(wù)

CallerRunsPolicy:由調(diào)用線程處理該任務(wù)

(四)線程池執(zhí)行流程

當(dāng)我們了解了ThreadPoolExecutor的七個參數(shù)后,我們就可以很快的理解線程池的流程:

線程池主要參數(shù)有哪些

當(dāng)提交任務(wù)后,首先判斷當(dāng)前線程數(shù)是否超過核心線程數(shù),如果沒超過則創(chuàng)建新線程執(zhí)行任務(wù),否則判斷工作隊列是否已滿,如果未滿則將任務(wù)添加到隊列中,否則判斷線程數(shù)是否超過最大線程數(shù),如果未超過則創(chuàng)建線程執(zhí)行任務(wù),否則執(zhí)行拒絕策略。

(五)Executors提供的線程池

executors提供了許多種線程池供用戶使用,雖然很多公司禁止使用executors創(chuàng)建線程池,但是對于剛開始解除線程池的人來說,Executors類所提供的線程池能很好的帶你進入多線程的世界。

5.1 newSingleThreadExecutor

ExecutorService executorService = Executors.newSingleThreadExecutor();

聽名字就可以知道這是一個單線程的線程池,在這個線程池中只有一個線程在工作,相當(dāng)于單線程執(zhí)行所有任務(wù),此線程可以保證所有任務(wù)的執(zhí)行順序按照提交順序執(zhí)行,看構(gòu)造方法也可以看出,corePoolSize和maximumPoolSize都是1。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

5.2 newFixedThreadPool

ExecutorService executorService = Executors.newFixedThreadPool(2);

固定長度的線程池,線程池的長度在創(chuàng)建時通過變量傳入。下面是newFixedThreadPool的構(gòu)造方法,corePoolSize和maximumPoolSize都是傳入的參數(shù)值

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

5.3 newCachedThreadPool

ExecutorService executorService = Executors.newCachedThreadPool();

可緩存線程池,這個線程池設(shè)定keepAliveTime為60秒,并且對最大線程數(shù)量幾乎不做控制。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

觀察構(gòu)造方法,corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即線程數(shù)量幾乎無限制。設(shè)定keepAliveTime 為60秒,線程空閑60秒后自動結(jié)束,因為該線程池創(chuàng)建無限制,不會有隊列等待,所以使用SynchronousQueue同步隊列。

5.4 newScheduledThreadPool

創(chuàng)建一個定時的線程池。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求。下面是newScheduledThreadPool的用法:

Thread thread1=new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"thread1");
    }
});
Thread thread2=new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"thread2");
    }
});
Thread thread3=new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"thread3");
    }
});
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
//在1000ms后執(zhí)行thread1
scheduledExecutorService.schedule(thread1,1000,TimeUnit.MILLISECONDS);
//在1000ms后每隔1000ms執(zhí)行一次thread2,如果任務(wù)執(zhí)行時間比間隔時間長,則延遲執(zhí)行
scheduledExecutorService.scheduleAtFixedRate(thread2,1000,1000,TimeUnit.MILLISECONDS);
//和第二種方式類似,但下一次任務(wù)開始的時間為:上一次任務(wù)結(jié)束時間(而不是開始時間) + delay時間
scheduledExecutorService.scheduleWithFixedDelay(thread3,1000,1000,TimeUnit.MILLISECONDS);

(六)為什么阿里巴巴禁止程序員用Exectors創(chuàng)建線程池

如果你的idea裝了Alibaba Java Codeing Guidelines插件(推薦大家使用,有助于讓你的代碼更加規(guī)范),那么當(dāng)你寫了Exectors創(chuàng)建線程池后會看到提示:

線程池主要參數(shù)有哪些

并且阿里將這個用法定義為Blocker,即不允許使用,而是讓人們用ThreadPoolExecutor的方式創(chuàng)建線程池。原因是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的人更加明確線程池的運行規(guī)則,規(guī)避資源耗盡的風(fēng)險。

線程池主要參數(shù)有哪些

Executors返回的線程池對象的弊端如下:

1)FixedThreadPool和SingleThreadPool:

??允許的請求隊列長度為Integer.MAX_VALUE,可能會堆積大量的請求,從而導(dǎo)致OOM。 ?? 2)CachedThreadPool:

??允許的創(chuàng)建線程數(shù)量為Integer.MAX_VALUE,可能會創(chuàng)建大量的線程,從而導(dǎo)致OOM。 ?? 下面是ThreadPoolExecutor創(chuàng)建線程池的簡單例子

int corePoolSize=5;
int maximumPoolSize=10;
long keepAliveTime=30;
BlockingQueue<Runnable> blockingQueue=new ArrayBlockingQueue(2);
RejectedExecutionHandler handler=new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, blockingQueue, handler);
threadPoolExecutor.execute(thread1);

(七)在SpringBoot項目中使用線程池

SpringBoot對線程池又做了一層封裝,在SpringBoot中,可以通過ThreadPoolTaskExecutor類來創(chuàng)建線程池。需要注意兩者的區(qū)別ThreadPoolExecutor時JUC包下的類,ThreadPoolTaskExecutor是springframework包下的類。但原理都是一樣的。

7.1 項目搭建

首先搭建一個SpringBoot項目,只需要引入web依賴即可

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

7.2 配置文件配置

線程池的參數(shù)盡量寫到配置文件里,這樣就能根據(jù)需要進行修改,在application.properties文件中配置:

myExecutor.corePoolSize=5
myExecutor.maxPoolSize=10
myExecutor.keepAliveSeconds=30
myExecutor.allowCoreThreadTimeOut=false
myExecutor.queueCapacity=20
myExecutor.threadNamePrefix=myExecutor-

7.3 編寫一個自己的線程池

新建一個包叫config,新建類ExecutorConfig ,首先參數(shù)的值從配置文件中獲取,接著用ThreadPoolTaskExecutor 創(chuàng)建一個自己的線程池,注入到Bean容器中。

@Configuration
@EnableAsync
public class ExecutorConfig {

    @Value("${myExecutor.corePoolSize}")
    private int corePoolSize;
    @Value("${myExecutor.maxPoolSize}")
    private int maxPoolSize;
    @Value("${myExecutor.keepAliveSeconds}")
    private int keepAliveSeconds;
    @Value("${myExecutor.allowCoreThreadTimeOut}")
    private boolean allowCoreThreadTimeOut;
    @Value("${myExecutor.queueCapacity}")
    private int queueCapacity;
    @Value("${myExecutor.threadNamePrefix}")
    private String threadNamePrefix;

    @Bean("myExecutor")
    public Executor myExecutor(){
        ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
        //核心線程數(shù)
        executor.setCorePoolSize(corePoolSize);
        //最大線程數(shù)
        executor.setMaxPoolSize(maxPoolSize);
        //線程空閑時間
        executor.setKeepAliveSeconds(keepAliveSeconds);
        //是否保留核心線程數(shù)
        executor.setAllowCoreThreadTimeOut(allowCoreThreadTimeOut);
        //隊列長度
        executor.setQueueCapacity(queueCapacity);
        //拒絕策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //設(shè)置線程名稱前綴
        executor.setThreadNamePrefix(threadNamePrefix);
        executor.initialize();
        return executor;
    }
}

這里需要注意的是有一個方法setAllowCoreThreadTimeOut,當(dāng)傳入?yún)?shù)為true時,所有線程超時后都會被銷毀,如果為false,只有超過核心線程數(shù)并且超時時才會被銷毀。

7.4 編寫service并使用

首先寫一個service接口:

public interface DoSomeThing {
    /**
     * 通過線程池異步執(zhí)行耗時的任務(wù)
     */
    public void doSomeThing();
}

再編寫實現(xiàn)類:

@Service
public class DoSomeThingImpl implements DoSomeThing {

    @Override
    @Async("myExecutor")
    public void doSomeThing() {
        System.out.println(Thread.currentThread().getName()+"-in");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"-out");
    }
}

增加注解@Async("myExecutor")后,這段方法就會異步由myExecutor線程池執(zhí)行。

7.5 編寫一個controller

新建一個IndexController,每次請求執(zhí)行一次doSomeThing()方法。

@RestController
public class IndexController {

    @Autowired
    private DoSomeThing doSomeThing;

    @RequestMapping(value = "/index",method = RequestMethod.GET)
    public String index(){
        doSomeThing.doSomeThing();
        return "success";
    }
}

7.6 測試

訪問十次http://localhost:8080/index,由于設(shè)置的核心線程數(shù)是5,隊列容量是30,因此最多只會用到5個線程資源,結(jié)果如下:

線程池主要參數(shù)有哪些

到此,關(guān)于“線程池主要參數(shù)有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI