springboot-@Async默认线程池导致OOM问题
内存溢出的三种类型:
1.第一种OutOfMemoryError: PermGen space,发生这种问题的原意是程序中使用了大量的jar或class
2.第二种OutOfMemoryError: Java heap space,发生这种问题的原因是java虚拟机创建的对象太多
3.第三种OutOfMemoryError:unable to create new native thread,创建线程数量太多,占用内存过大
@Async注解
@async注解的方法不能跟调用者的方法在一个类里面.不然会造成不生效.可以理解为一个类就是一个线程池,调用者的方法就是一个线程,这里需要单独开一个线程去调用
自定义线程池
@Bean
public Executor taskThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(threadNamePrefix);
executor.setAwaitTerminationSeconds(awaitTerminationSeconds);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
@Async默认使用Bean Name为executor的线程池。也可以根据Bean Name指定特定线程池
@Async("taskThreadPool")
public void asyncMethod() {
}
SimpleAsyncTaskExecutor
Async注解默认使用的是 SimpleAsyncTaskExecutor 该线程池默认来一个任务创建一个线程
在压测的情况下,该线程池默认来一个任务创建一个线程,这时就会不断创建大量线程,
SimpleAsyncTaskExecutor提供了限流机制
通过concurrencyLimit属性来控制开关,当concurrencyLimit>=0时开启限流机制,默认
关闭限流机制即concurrencyLimit=-1,当关闭情况下,会不断创建新的线程来处理任务
首先任务进来,会循环判断当前执行线程数是否超过concurrencyLimit,如果超了,则当前线程调用wait方法,释放monitor对象锁,进入等待
线程任务执行完毕后,当前执行线程数会减一,会调用monitor对象的notify方法,唤醒等待状态下的线程,等待状态下的线程会竞争monitor锁,竞争到,会继续执行线程任务
@Configuration
@EnableAsync
public class AsyncCommonConfig extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
//设置允许同时执行的线程数为10
executor.setConcurrencyLimit(10);
return executor;
}
}
1.开启限流情况下,能有效控制应用线程数
2.虽然可以有效控制线程数,但执行效率会降低,会出现主线程等待,线程竞争的情况。
3.限流机制适用于任务处理比较快的场景,对于应用处理时间比较慢的场景并不适用。