SpringBoot项目配置线程池

其实配置线程池没什么好讲的,就那几个参数,不过在项目包中提供了一个帮助类,可以方便的只用传参数,方法内部去构建线程池对象,避免配置多个线程池时每个方法内部产生大量重复代码.

准备

Spring提供了一些类可以帮助我们快速构建线程池bean对象。

  1. 基于线程池任务的org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
  2. 基于定时任务使用的调度线程池对象org.springframework.scheduling.TaskScheduler

我们现在提供一个类ThreadBuilderHelper,专门用户构建上述的线程池对象。内部代码很简单,主要就是为了避免重复代码,所以在这个类中统一处理参数赋值,由于重载了几个,所以看起来比较多而已。

package com.ddf.boot.common.core.helper;

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 创建线程
 * <p>
 * _ooOoo_
 * o8888888o
 * 88" . "88
 * (| -_- |)
 * O\ = /O
 * ___/`---'\____
 * .   ' \\| |// `.
 * / \\||| : |||// \
 * / _||||| -:- |||||- \
 * | | \\\ - /// | |
 * | \_| ''\---/'' | |
 * \ .-\__ `-` ___/-. /
 * ___`. .' /--.--\ `. . __
 * ."" '< `.___\_<|>_/___.' >'"".
 * | | : `- \`.;`\ _ /`;.`/ - ` : | |
 * \ \ `-. \_ __\ /__ _/ .-` / /
 * ======`-.____`-.___\_____/___.-`____.-'======
 * `=---='
 * .............................................
 * 佛曰:bug泛滥,我已瘫痪!
 *
 * @author dongfang.ding
 * @date 2019/12/11 0011 17:52
 */
public class ThreadBuilderHelper {

    /**
     * 构建线程池参数, 默认拒绝策略是将请求打回给调用线程使用
     *
     * @param prefix           线程池名称前缀
     * @param keepAliveSeconds 保持空闲时间
     * @param queueCapacity    队列大小
     * @return
     */
    public static ThreadPoolTaskExecutor buildThreadExecutor(String prefix, int keepAliveSeconds, int queueCapacity) {
        return buildThreadExecutor(prefix, keepAliveSeconds, queueCapacity,
                Runtime.getRuntime().availableProcessors() + 1, Runtime.getRuntime().availableProcessors() * 2,
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }


    /**
     * 构建线程池参数, 默认拒绝策略是将请求打回给调用线程使用
     *
     * @param prefix           线程池名称前缀
     * @param keepAliveSeconds 保持空闲时间
     * @param queueCapacity    队列大小
     * @param corePoolSize     核心线程池大小
     * @param maxPoolSize      最大线程池大小
     * @return org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
     * @author dongfang.ding
     * @date 2019/12/11 0011 17:59
     **/
    public static ThreadPoolTaskExecutor buildThreadExecutor(String prefix, int keepAliveSeconds, int queueCapacity,
            int corePoolSize, int maxPoolSize) {
        return buildThreadExecutor(prefix, keepAliveSeconds, queueCapacity, corePoolSize, maxPoolSize,
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }


    /**
     * 构建线程池参数
     *
     * @param prefix           线程池名称前缀
     * @param keepAliveSeconds 保持空闲时间
     * @param queueCapacity    队列大小
     * @return
     */
    public static ThreadPoolTaskExecutor buildThreadExecutor(String prefix, int keepAliveSeconds, int queueCapacity,
            RejectedExecutionHandler rejectedExecutionHandler) {
        return buildThreadExecutor(prefix, keepAliveSeconds, queueCapacity,
                Runtime.getRuntime().availableProcessors() + 1, Runtime.getRuntime().availableProcessors() * 2,
                rejectedExecutionHandler
        );
    }

    /**
     * 构建线程池参数
     *
     * @param prefix                   线程池名称前缀
     * @param keepAliveSeconds         保持空闲时间
     * @param queueCapacity            队列大小
     * @param corePoolSize             核心线程池大小
     * @param maxPoolSize              最大线程池大小
     * @param rejectedExecutionHandler 队列满之后的处理策略
     * @return org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
     * @author dongfang.ding
     * @date 2019/12/11 0011 17:59
     **/
    public static ThreadPoolTaskExecutor buildThreadExecutor(String prefix, int keepAliveSeconds, int queueCapacity,
            int corePoolSize, int maxPoolSize, RejectedExecutionHandler rejectedExecutionHandler) {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setThreadNamePrefix(prefix);
        threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
        threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
        threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
        threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
        threadPoolTaskExecutor.setRejectedExecutionHandler(rejectedExecutionHandler);
        return threadPoolTaskExecutor;
    }



    /**
     * 构建定时任务线程池
     *
     * @param prefix
     * @param keepAliveSeconds
     * @return
     */
    public static ScheduledThreadPoolExecutor buildScheduledExecutorService(String prefix, int keepAliveSeconds) {
        return buildScheduledExecutorService(prefix, Runtime.getRuntime().availableProcessors() + 1,
                Runtime.getRuntime().availableProcessors() * 2, keepAliveSeconds
        );
    }

    /**
     * 构建定时任务线程池
     *
     * @param prefix
     * @param corePoolSize
     * @param maxPoolSize
     * @return
     */
    public static ScheduledThreadPoolExecutor buildScheduledExecutorService(String prefix, int corePoolSize,
            int maxPoolSize, int keepAliveSeconds) {
        ThreadFactory namedThreadFactory = new CustomizableThreadFactory(prefix);
        ScheduledThreadPoolExecutor scheduledExecutorService = new ScheduledThreadPoolExecutor(corePoolSize,
                namedThreadFactory
        );
        scheduledExecutorService.setMaximumPoolSize(maxPoolSize);
        scheduledExecutorService.setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS);
        return scheduledExecutorService;
    }
}

定义和使用

将线程池对象注入到配置类中,这个由于是在通用包中,因此线程池对象加了注解@Primary, 当使用方也自定义线程池,但是没有指定具体用哪个的时候,可以用这个默认的来兜底。这个就是一个全局的默认线程池。当然如果还需要在项目其它地方定义的话,按照下面这种方式,但是不要加@Primary即可。
注意,单独这个功能@EnableAsync是不需要的。

@Configuration
@EnableAsync
@EnableScheduling
public class CoreWebConfig {
    /**
     * 默认线程池
     *
     * @return
     */
    @Bean
    @Primary
    public ThreadPoolTaskExecutor defaultThreadPool() {
        return ThreadBuilderHelper.buildThreadExecutor("default-thread-pool", 60, 1000);
    }

    /**
     * 定时任务调度线程池
     *
     * @return
     */
    @Bean
    @Primary
    public TaskScheduler scheduledExecutorService() {
        ThreadPoolTaskScheduler threadPoolScheduler = new ThreadPoolTaskScheduler();
        threadPoolScheduler.setThreadNamePrefix("scheduledExecutorService-");
        threadPoolScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
        threadPoolScheduler.setRemoveOnCancelPolicy(true);
        return threadPoolScheduler;
    }
}

在其它容器类中,需要想要使用线程池,则直接注入即可.

@Service
public class BizService {
	
	@Autowired
	private ThreadPoolTaskExecutor defaultThreadPool;
	
	public void doBiz() {
		defaultThreadPool.execute(() -> {
			// do something
		});
	}
}

当然还有一些方法,天生就是异步的,不想使用上面的那种方式,那么由于上面的配置类开启了注解@EnableAsync,那么可以在方法上标识一个方法为异步方法,并指定线程池bean的名称。
然后其他业务类直接调用这个方法即可,但是要注意,采用这种方式的时候调用代码不能和被调用方在一个类中,否则代理会失效。

@Component
public class AsyncTask {
    @Async(value = "defaultThreadPool")
    public void doBiz {
		// do something
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值