头图

背景
最近看代码时看到小伙伴提交了这样一段代码
scala 代码解读复制代码public class AsyncExecutorConfig extends AsyncConfigurerSupport {

@Override
public Executor getAsyncExecutor() {
    return new ThreadPoolExecutor(
            10,
            300,
            30,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(2000),
            ThreadFactoryBuilder.create().setNamePrefix("bid-async-").build(),
            new ThreadPoolExecutor.CallerRunsPolicy());
}

代码的目的是重新实现@Aysnc的默认线程处理,于是有一个疑问,为什么要进行重写,使用默认实现不可以吗?@Async默认的实现方式是什么?原理又是什么呢?
带着这个疑问进行了相关探索
探索
从修改默认实现上看,默认实现一定也是一个线程池,于是查看他的默认线程池是什么?首先我看到的默认实现是会使用SimpleAsyncTaskExecutor线程池,那看SimpleAsyncTaskExecutor线程池的实现方式,他的方式是有一个任务就去创建一个线程,而且创建的线程不会复用且不会销毁,当任务过多时,会出现cpu过高的情况,基于此,原有的实现是一定存在问题的。
随着探索的加深,发现存在另一个答案,就是他的实现也是ThreadPoolExecutor,在springboot2.1.0之前默认是实现是SimpleAsyncTaskExecutor,2.1.0之后默认实现变更为ThreadPoolExecutor,我们看看变更之后是怎么实现默认线程池的
kotlin 代码解读复制代码@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {

/**
 * Bean name of the application {@link TaskExecutor}.
 */
public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";

private final TaskExecutionProperties properties;

private final ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers;

private final ObjectProvider<TaskDecorator> taskDecorator;

public TaskExecutionAutoConfiguration(TaskExecutionProperties properties,
        ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
        ObjectProvider<TaskDecorator> taskDecorator) {
    this.properties = properties;
    this.taskExecutorCustomizers = taskExecutorCustomizers;
    this.taskDecorator = taskDecorator;
}
    
    
    

kotlin 代码解读复制代码protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {

    BlockingQueue<Runnable> queue = this.createQueue(this.queueCapacity);
    ThreadPoolExecutor executor;
    if (this.taskDecorator != null) {
        executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, (long)this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler) {
            public void execute(Runnable command) {
                Runnable decorated = ThreadPoolTaskExecutor.this.taskDecorator.decorate(command);
                if (decorated != command) {
                    ThreadPoolTaskExecutor.this.decoratedTaskMap.put(decorated, command);
                }

                super.execute(decorated);
            }
        };
    } else {
        executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, (long)this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler);
    }

默认线程池的定义了核心线程数,最大线程数,队列以及线程存活时间,他们的参数分别为

核心线程数:8
最大线程数:int的最大值
队列:阻塞队列且最大值为int的最大值
线程存活时间:60s
拒绝策略:AbortPolicy

对比上一个默认实现,一个很大的进步是线程是可以重复利用的,这样就大大减少了资源的使用,但是还是存在一个较大的风险,就是队列长度过长,当任务过多时会将大量待执行的任务放到队列里面,导致程序处理不过来,最大线程数其实没有利用起来,所以保险起见,还是要自己手动实现一个线程池,防止出现相关问题

图片

结语
线程池可以很好的提高功能的效率,但是也要考虑使用过程中出现的问题,比如多线程写,又比如使用不当造成的系统性能问题,基于此,是很有必要了解他们的执行方式和原理
转载来源:https://juejin.cn/post/7370963861644771337


运维社
12 声望4 粉丝