SpringBoot 多线程池之间隔离

Java
532
0
0
2022-10-22
标签   SpringBoot

使用场景

应用中有两种不同类型的异步,产品的和订单的,在某一瞬间,大量涌入了订单的异步任务,这样,根据线程池的配置,订单的异步任务占满了线程池以后,就会影响产品的异步任务进入线程池,导致产品的功能异常。

解决办法

一个比较好的方案是:把产品和订单隔离开,使用两个独立的线程池,避免互相影响。

定义不同线程池

@Configuration
@EnableAsync
public class ThreadPoolConfig {

    @Value("${myThreadPool.maxPoolSize}") 
    private Integer maxPoolSize;
    @Value("${myThreadPool.queueCapacity}") 
    private Integer queueCapacity;
    @Value("${myThreadPool.keepAliveSeconds}") 
    private Integer keepAliveSeconds;
    @Value("${myThreadPool.waitForTasksToCompleteOnShutdown}") 
    private Boolean waitForTasksToCompleteOnShutdown;

    @Bean("orderPool") 
    public Executor orderExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数等于系统核数
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        // 设置核心线程数
        executor.setCorePoolSize(availableProcessors);
        // executor.setCorePoolSize(corePoolSize); 
        // 设置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        // 设置队列大小
        executor.setQueueCapacity(queueCapacity);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程满了之后由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 设置默认线程名称
        executor.setThreadNamePrefix("threadPool");
        // 等待所有任务执行完成后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        // 执行初始化
        executor.initialize();
        return executor;
    }

    @Bean("productPool") 
    public Executor productExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        executor.setCorePoolSize(availableProcessors);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setThreadNamePrefix("productPool");
        executor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        executor.initialize();
        return executor;
    }
}

yml 配置内容如下

myThreadPool: 
  maxPoolSize: 20 
  queueCapacity: 2048 
  keepAliveSeconds: 60 
  waitForTasksToCompleteOnShutdown: true

定义服务类

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Async("orderPool")
    @Override
    public void getOrder() {
        log.info("getOrder, current thread is {}",Thread.currentThread().getName());
    }
}
@Service
@Slf4j
public class ProductServiceImpl implements ProductService {
    @Async("productPool")
    @Override
    public void getProduct() {
        log.info("getProduct, current thread is {}",Thread.currentThread().getName());
    }
}

测试

@Test
public void multiPoolThreadTest() {
    for (int i = 0; i < 10; i++) {
        orderService.getOrder();
        productService.getProduct();
    }
}

测试结果如下

SpringBoot 多线程池之间隔离