ThreadPoolExecutor簡述

ThreadPoolExecutor 的使用

線程池使用代碼如下:

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(100));
threadPoolExecutor.execute(new Runnable() {
    @Override
    public void run() {
        // 執行線程池
        System.out.println("test...");
    }
});

ThreadPoolExecutor說明

ThreadPoolExecutor 構造方法有以下四個,如下圖所示:

在這裏插入圖片描述

其中最後一個構造方法有 7 個構造參數,包含了前三個方法的構造參數,這 7 個參數名稱如下所示:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    //...
}

其代表的含義如下:

  • ① corePoolSize
    線程池中的核心線程數,默認情況下核心線程一直存活在線程池中,如果將 ThreadPoolExecutor 的 allowCoreThreadTimeOut 屬性設爲 true,如果線程池一直閒置並超過了 keepAliveTime 所指定的時間,核心線程就會被終止。

  • ② maximumPoolSize
    線程池中最大線程數,如果活動的線程達到這個數值以後,後續的新任務將會被阻塞(放入任務隊列)。

  • ③ keepAliveTime
    線程池的閒置超時時間,默認情況下對非核心線程生效,如果閒置時間超過這個時間,非核心線程就會被回收。如果 ThreadPoolExecutor 的 allowCoreThreadTimeOut 設爲 true 的時候,核心線程如果超過閒置時長也會被回收。

  • ④ unit
    配合 keepAliveTime 使用,用來標識 keepAliveTime 的時間單位。

  • ⑤ workQueue
    線程池中的任務隊列,使用 execute() 或 submit() 方法提交的任務都會存儲在此隊列中。

  • ⑥ threadFactory
    爲線程池提供創建新線程的線程工廠。

  • ⑦ rejectedExecutionHandler
    線程池任務隊列超過最大值之後的拒絕策略,RejectedExecutionHandler 是一個接口,裏面只有一個 rejectedExecution 方法,可在此方法內添加任務超出最大值的事件處理。ThreadPoolExecutor 也提供了 4 種默認的拒絕策略:

    • new ThreadPoolExecutor.DiscardPolicy():丟棄掉該任務,不進行處理
    • new ThreadPoolExecutor.DiscardOldestPolicy():丟棄隊列裏最近的一個任務,並執行當前任務
    • new ThreadPoolExecutor.AbortPolicy():直接拋出 RejectedExecutionException 異常
    • new ThreadPoolExecutor.CallerRunsPolicy():既不拋棄任務也不拋出異常,直接使用主線程來執行此任務

自定義線程池以及拒絕策略

直接上代碼吧…

package cn.fxbin.learn.config;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.*;

/**
 * ThreadPoolConfig
 *
 * @author fxbin
 * @version v1.0
 * @since 2019/12/17 0:59
 */
@Slf4j
@Configuration
public class ThreadPoolConfig {

    private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;
    private static final RejectedExecutionHandler DEFAULT_HANDLER = new ReTryAndLogPolicy();

    @Bean(value = "queueThreadPool")
    public ExecutorService queueThreadPool(){
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("queue-thread-%d").build();

        ExecutorService pool = new ThreadPoolExecutor(4, 17, 60, DEFAULT_TIME_UNIT,
                new ArrayBlockingQueue<Runnable>(1000),namedThreadFactory, DEFAULT_HANDLER);
        return pool ;
    }

    
    /**
     * ReTryAndLogPolicy
     * 
     * 參考:
     * <p>
     * 1. CallerRunsPolicy :這個策略重試添加當前的任務,他會自動重複調用 execute() 方法,直到成功。
     * 2. AbortPolicy :對拒絕任務拋棄處理,並且拋出異常。
     * 3. DiscardPolicy :對拒絕任務直接無聲拋棄,沒有異常信息。
     * 4. DiscardOldestPolicy :對拒絕任務不拋棄,而是拋棄隊列裏面等待最久的一個線程,然後把拒絕任務加到隊列。
     * </p>
     * 
     * @author fxbin
     * @since 2019/12/17 0:59
     */
    public static class ReTryAndLogPolicy extends ThreadPoolExecutor.CallerRunsPolicy {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            super.rejectedExecution(r, executor);

            ThreadFactory factory = executor.getThreadFactory();
            String threadNamePrefix = "";
            if (factory.getClass() == CustomizableThreadFactory.class) {
                CustomizableThreadFactory factory1 = (CustomizableThreadFactory) factory;
                threadNamePrefix = factory1.getThreadNamePrefix();
            }

            log.info("executor info:{}", executor.toString());
            log.error("threadNamePrefix {}, corePoolSize {}, maxPoolSize {}, workQueueSize {}, rejected task {}.",
                    new Object[]{threadNamePrefix, executor.getCorePoolSize(), executor.getMaximumPoolSize(), executor.getQueue().size(), r.toString()});

        }
    }
}

歡迎關注博主公衆號:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章