Spring Boot 线程池应用与配置

启动类注解@EnableAsync

@EnableAsync
@SpringBootApplication
public class ThreadSampleApplication {
 
	public static void main(String[] args) {
		SpringApplication.run(ThreadSampleApplication.class, args);
	}
 
}

自定义线程池

业务量较大时,需要自定义线程池配置,否则spring会使用默认线程池,最大线程数没有限制,如果线程没有正确结束,最终会导致内存溢出.

线程池的流程:

  1. 当线程数小于核心线程数时,创建线程.
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列.
  3. 当线程数大于等于核心线程数,且任务队列已满时分两种情况:
  • 若线程数小于最大线程数,创建线程.
  • 若线程数等于最大线程数,执行拒绝策略.
@Configuration
@EnableAsync 
public class ThreadPoolConfig {

	// 当前机器的CPU核心数
    private static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
    
    /**
     * 任务提交时 CorePoolSize –> QueueCapacity –> MaxPoolSize –> 拒绝策略
     */
    @Bean(name = "threadPoolTaskExecutor")
    public Executor asyncServiceThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(AVAILABLE_PROCESSORS + 1);//线程池核心线程,正常情况下开启的线程数. CPU核数 + 1
        executor.setQueueCapacity(AVAILABLE_PROCESSORS * 10);//线程队列容量。当核心线程数都被占用,多余的任务会存到此处
        executor.setMaxPoolSize(AVAILABLE_PROCESSORS * 2);//最大线程数
        executor.setKeepAliveSeconds(3600);//设置线程活跃时间(线程池中空闲线程等待工作的超时时间)
        executor.setThreadNamePrefix("threadPoolTaskExecutor-");//线程名字前缀
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//设置拒绝策略
        executor.setAllowCoreThreadTimeOut(true);//设置核心线程池超时关闭,默认false一直存在
        executor.setKeepAliveSeconds(300);//设置普通线程超时关闭时间
        executor.initialize();
        return executor;
    }
}

在异步执行的方法上加注解@Async,name指定使用自定义线程池配置

    /**
     * 使用自定义线程池
     */
    @Async("threadPoolTaskExecutor")
    public void doAsyncJob() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(1000);
                System.out.println(i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

拒绝策略 setRejectedExecutionHandler()

它是RejectedExecutionHandler类型的变量,表示线程池的饱和策略。如果阻塞队列(QueueCapacity)满了并且没有空闲的线程,这时如果继续提交任务,就需要采取一种策略处理该任务。

线程池提供了4种拒绝策略:

  • AbortPolicy:直接抛出异常,这是默认策略.
  • CallerRunsPolicy:用调用者所在的线程来执行任务.
  • DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务.
  • DiscardPolicy:直接丢弃任务.

注意:@Async失效情况:

  • 注解@Async的方法不是public方法

  • 注解@Async的返回值只能为void或者Future

  • 注解@Async方法使用static修饰也会失效

  • 没加注解@Async 或 @EnableAsync注解,导致spring无法扫描到异步类

  • 调用方与被调方不能在同一个类:Spring在扫描bean的时候会扫描方法上是否包含@Async注解,动态地生成一个子类(即proxy代理类),当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用时增加异步作用
    如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个 bean, 所以调用方与被调方不能在同一个类,一般将要异步执行的方法单独抽取成一个类,类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象.

  • 在Async 方法上标注@Transactional是没用的,但在Async 方法调用的方法上标注@Transactional 是有效的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之一丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值