自定义线程池
一、是有线程池的优点
1、使用线程池可以减少线程的创建和销毁,提高性能!!
2、,每次启动线程,springboot都会从新创建一个线程,线程不重用,显然效率太低,这是因为spring boot自带线程池过于简单,所以在开发中,都会自己配置线程池的属性
二、配置原理
@Configuration
public class AsyncPoolConfig implements AsyncConfigurer {
//把这个方法的返回对象 交给spring ioc管理
@Bean//<bean id="getAsyncExecutor" class="">
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//核心线程数:线程池刚创建的时候 就会初始化10个线程
threadPoolTaskExecutor.setCorePoolSize(10);
//非核心线程:15-10=5 核心线程不够用的时候
threadPoolTaskExecutor.setMaxPoolSize(15);
//缓冲队列的个数 :队列作为一个缓冲的工具,
//当没有足够的线程去处理任务时,可以将任务放进队列中,以队列先进先出的特性来执行工作任务
threadPoolTaskExecutor.setQueueCapacity(20);
//非核心线程数 还回去的时间 如果空闲超过10秒就被回收
threadPoolTaskExecutor.setKeepAliveSeconds(10);
//设置线程的前缀名称
threadPoolTaskExecutor.setThreadNamePrefix("zqs_");
//用来设置线程池关闭的时候等待所有任务都完成(可以设置时间)
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
//设置上面的时间
threadPoolTaskExecutor.setAwaitTerminationSeconds(100);
//拒绝策略:线程池都忙不过来的时候,可以适当选择拒绝
/**
* ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常
* ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常
* ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列
* ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务
*/
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//初始化线程池
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
三、拒绝策略
3.1、队列满了丢任务抛异常(默认)
ThreadPoolExecutor.AbortPolicy()
3.2、队列满了丢任务不抛异常
ThreadPoolExecutor.DiscardPolicy();
这里用的多得是 “广撒网”–》尽管多的发布给用户,推销自己的产品
3.3、将最早进入队列的任务删,之后再尝试加入队列
ThreadPoolExecutor.DiscardOldestPolicy();
这里主要是弹幕问题,弹幕太多,最早的弹幕可能额会提前删除
3.4、添加到线程池失败,那么主线程会自己去执行该任务
ThreadPoolExecutor.CallerRunsPolicy()
这样保证了任务的不会丢失,但是会出现卡顿问题
四、使用修改后的线程
五、线程异常(有无返回值的区别)
/**
* @ClassName
* @Description TODO
* @Author ZQS
* @Date 2020/8/31 0031 22:09
* @Version 1.0
**/
@RestController
@Slf4j
public class AsyncController {
@Autowired
private AsyncDemo asyncDemo;
@GetMapping("async1")
public String async1() throws ExecutionException, InterruptedException {
asyncDemo.asyncNoResult();
return "方法调用成功";
}
@GetMapping("async2")
public String async2() throws InterruptedException, ExecutionException {
Future<String> stringFuture = asyncDemo.asyncResult();
String s = stringFuture.get();
log.info("调用有返回值的异步方法"+s);
return "方法调用成功";
}
}
5.1、调用有返回值的线程异常
直接就会报异常出来,控制台或者日志可以看出来
5.2、调用没有返回值的线程异常
如果报异常是不好观察出来的
所以尽量调用没有返回值线程的时候不能写错
5.3、处理
1、线下的时候:通过日志等观察
2、线上的时候:通过发邮箱的方法最终是以controller层的异常为准