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

        }
    }
}
posted @ 2019-12-17 00:55  大痴小乙  阅读(213)  评论(0)    收藏  举报