阿里巴巴規范:手動創建線程池,效果會更好哦 的解決辦法,手動創建線程池ThreadPoolExecutor


手動創建線程池

在使用Executors創建線程時,阿里巴巴規范提出了手動創建線程池,效果會更好哦。 使用ThreadPoolExecutor方式創建線程池,可以規避資源耗盡風險(OOM)

ThreadPoolExecutor的構造函數

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;
    }

Alibaba規范警告信息

線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。 說明:Executors返回的線程池對象的弊端如下:
1)FixedThreadPool和SingleThreadPool:
  允許的請求隊列長度為Integer.MAX_VALUE,可能會堆積大量的請求,從而導致OOM。
2)CachedThreadPool:
  允許的創建線程數量為Integer.MAX_VALUE,可能會創建大量的線程,從而導致OOM。
            
Positive example 1:
    //org.apache.commons.lang3.concurrent.BasicThreadFactory
    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
        new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
       
        
            
Positive example 2:
    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
        .setNameFormat("demo-pool-%d").build();

    //Common Thread Pool
    ExecutorService pool = new ThreadPoolExecutor(5, 200,
        0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

    pool.execute(()-> System.out.println(Thread.currentThread().getName()));
    pool.shutdown();//gracefully shutdown
       
        
            
Positive example 3:
    <bean id="userThreadPool"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="10" />
        <property name="maxPoolSize" value="100" />
        <property name="queueCapacity" value="2000" />

    <property name="threadFactory" value= threadFactory />
        <property name="rejectedExecutionHandler">
            <ref local="rejectedExecutionHandler" />
        </property>
    </bean>
    //in code
    userThreadPool.execute(thread);

線程執行的邏輯圖與說明

邏輯圖

202112041259093 (1)

邏輯說明

  • 判斷核心線程數是否已滿,核心線程數大小和corePoolSize參數有關
  • 若核心線程池已滿,判斷隊列是否滿,隊列是否滿和workQueue參數有關
  • 若隊列已滿,判斷線程池是否已滿,線程池是否已滿和maximumPoolSize參數有關
  • 若線程池已滿,則采用拒絕策略處理無法執執行的任務,拒絕策略和handler參數有關

ThreadPoolExecutor的構造方法參數說明:

  • corePoolSize => 線程池核心線程數量,他來決定新的任務是創建新線程執行,還是丟到workQueue任務隊列中去
  • maximumPoolSize => 線程池最大數量,這個參數會根據你使用的workQueue任務隊列的類型,決定線程池創建的最大數量
  • keepAliveTime => 空閑線程存活時間,當空閑線程數量超過corePoolSize時,多余線程會在到存活時間時被銷毀
  • unit => 時間單位,keepAliveTime的時間單位
  • workQueue => 線程池所使用的任務隊列,它被添加到線程池中,但尚未被執行的任務;它一般分為直接提交隊列、有界任務隊列、無界任務隊列、優先任務隊列幾種
  • threadFactory => 線程池創建線程使用的工廠,工廠名字等,一般用於默認即可
  • handler => 線程池對拒絕任務的處理策略,當任務太多,如何拒絕任務

我們可以使用Alibaba規范來創建線程

完整代碼

package com.demos.date.thread;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import java.util.concurrent.*;

public class Thread01 {
    public static void main(String[] args) {
        // 編寫線程的名字,一般使用默認即可,
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNamePrefix("demo-pool-%d").build();
        ExecutorService pool = new ThreadPoolExecutor(2, 200,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(1024),namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
        // 調用線程
        for (int i = 0; i < 4; i++) {
            pool.execute(()->{
                System.out.println(Thread.currentThread().getName()+Thread.currentThread().getId());
                pool.shutdown();
            });
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM