ThreadPoolExecutor线程池实战

Posted 爱叨叨的程序狗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadPoolExecutor线程池实战相关的知识,希望对你有一定的参考价值。

ThreadPoolExecutor线程池实战

Demo已开源至Github,threadDemo

1.配置TreadPoolProperty

ThreadPoolTaskExecutor构造方法:

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

在这里插入图片描述

为方便全局使用自定义线程池ThreadPoolTaskExecutor,我们建议使用将其初始化所需参数写入到yml/application配置文件中,以达到不入侵源码且改动线程池运行参数的目的。本文将使用 @ConfigurationProperties注解读取yml配置的方式初始化线程池构造方法。如对获取yml有疑问,可以查看我的另一篇文章,专门讲述了如何获取yml里配置的数据。当然如果您用做demo个人练习,也可以使用赋值的方式完成。

文章链接:如何获取yml里的配置数据?

构造方法参数

  • corePoolSize:核心线程数,一般取CPU物理核心数,线程默认一直存活
  • maximumPoolSize:最大容纳线程数,一般取核心线程数的2倍
  • keepAliveTime:非核心线程的闲置超时时间
  • unit:keepAliveTime闲置时间单位,一般取秒
  • queueCapacity:工作队列长度
  • awaitTerminationSeconds:设置此执行程序应该在关闭时阻止的最大秒数
  • threadNamePrefix:线程前缀名
  • RejectedExecutionHandler:线程池内阻塞队列已满,无法接受任务的拒绝策略

SpringThreadPoolPropertyConfig.class配置类

@ConfigurationProperties(prefix = "threadpool.property")
public class SpringThreadPoolPropertyConfig {

    private Integer corePoolSize;

    private Integer maxPoolSize;

    private Integer keepAliveSeconds;

    private Integer queueCapacity;

    private Integer awaitTerminationSeconds;

    private String threadNamePrefix;

    private Boolean waitForTasksToCompleteOnShutdown;
}

application.yml

threadpool:
  property:
    corePoolSize: 6
    maxPoolSize: 12
    keepAliveSeconds: 10
    queueCapacity: 1000
    awaitTerminationSeconds: 0
    threadNamePrefix: pool_
    waitForTasksToCompleteOnShutdown: true

SpringThreadPoolConfig.class线程池配置类

@Configuration
@EnableAsync
public class SpringThreadPoolConfig {

    @Autowired
    private SpringThreadPoolPropertyConfig threadPoolConfig;

    @Bean("taskExecutor")
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor customizeThreadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        customizeThreadPoolTaskExecutor.setCorePoolSize(threadPoolConfig.getCorePoolSize());
        customizeThreadPoolTaskExecutor.setMaxPoolSize(threadPoolConfig.getMaxPoolSize());
        customizeThreadPoolTaskExecutor.setKeepAliveSeconds(threadPoolConfig.getKeepAliveSeconds());
        customizeThreadPoolTaskExecutor.setQueueCapacity(threadPoolConfig.getQueueCapacity());
        customizeThreadPoolTaskExecutor.setAwaitTerminationSeconds(threadPoolConfig.getAwaitTerminationSeconds());
        customizeThreadPoolTaskExecutor.setThreadNamePrefix(threadPoolConfig.getThreadNamePrefix());
        customizeThreadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(threadPoolConfig.getWaitForTasksToCompleteOnShutdown());
        customizeThreadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return customizeThreadPoolTaskExecutor;
    }
}

配置完成


使用线程池

@Resource(name = "taskExecutor")

@Slf4j
@Service
public class AsyncServiceImpl implements AsyncService {

    @Resource(name = "taskExecutor")
    private ThreadPoolTaskExecutor taskExecutor;

    @Override
    public void processingTimeOperation() {

        /**
         *
         * 在此处理耗时操作业务逻辑,
         * 如数据量大的插入,只需要在业务层将List等段截取后的List在for循环中传入每一个List调用异步线程即可
         */
        try {
            log.info("进入异步");
            int activeCount = taskExecutor.getActiveCount();
            taskExecutor.submit(() -> log.info(String.valueOf(activeCount))).get();
            log.debug("当前线程信息:-{}", taskExecutor.getThreadNamePrefix() + taskExecutor.getActiveCount());
            log.info("异步体执行完成");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

taskExecutor.submit()中执行异步耗时操作,如大批量插入操作,submit()方法可以返回线程执行结果,无返回值的需求可以使用execute()方法。

注意事项:

1.异步操作相关逻辑需要单独在一个接口和实现类中完成。

2.@Async注解要使用在主线程的业务方法中,如果使用在处理耗时操作的逻辑中,会出现主线程完毕,不走子线程异步代码的问题。

具体可以参考上文Github地址中源码

本文涉及到自定义线程池理论知识部分请查看我的另一篇文章:

自定义线程池理论知识部分

以上是关于ThreadPoolExecutor线程池实战的主要内容,如果未能解决你的问题,请参考以下文章

Java 线程池 ThreadPoolExecutor源码简析

Java并发编程原理与实战三十七:线程池的原理与使用

Java—线程池ThreadPoolExecutor案例详解,高薪必备

Android Java 线程池 ThreadPoolExecutor源代码篇

Springboot线程池服务实战分享

Java中的线程池——ThreadPoolExecutor源代码分析