springboot多线程
多线程实现
1、要写⼀个配置类开启多线程
配置类实现AsyncConfigurer接⼝,并重写getAsyncExecutor()⽅法返回⼀个Executor,并⽤@EnableAsync注解标注。
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 核⼼线程⼤⼩
threadPoolTaskExecutor.setCorePoolSize(8);
// 最⼤线程⼤⼩
threadPoolTaskExecutor.setMaxPoolSize(16);
// 队列⼤⼩
threadPoolTaskExecutor.setQueueCapacity(50);
// 初始化
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
2、在需要多线程执⾏的⽅法上标注@Async注解
如果@Async标注在类上,则该类的所有⽅法都是异步⽅法。
@Service
@Async
public class AsyncService {
public void fun1(int i) {
System.out.println("fun1----" + i);
}
public void fun2(int i) {
System.out.println("fun2====" + i);
}
}
3、测试效果
@Controller
@RequestMapping("/hello")
public class HelloController {
@Autowired
private AsyncService asyncService;
@GetMapping("/testAsync")
public String testAsync() {
for (int i = 0; i < 100; i++) {
asyncService.fun1(i);
asyncService.fun2(i);
}
return "success";
}
}
访问该接⼝,输出结果就会看到多线程效果
// 部分输出结果
fun1----0
fun1----4
fun2====4
fun1----5
fun2====5
fun1----6
fun2====6
fun1----7
fun2====7
fun1----8
fun2====8
fun1----9
fun2====9
fun1----10
实际输出中的报错
springboot原理图解
抛出RejectedExecutionException拒绝执⾏异常。
urrent.RejectedExecutionException: Task urrent.FutureTask@24a8a5ec rejected from urrent.ThreadPoolExecutor@6719f3a5[Running, pool size = 16, active threads = 16, queued tasks = 50, completed tas  at urrent.jectedExecution(ThreadPoolExecutor.java:2063) ~[na:1.8.0_161]
at ject(ThreadPoolExecutor.java:830) [na:1.8.0_161]
at ute(ThreadPoolExecutor.java:1379) [na:1.8.0_161]
at urrent.AbstractExecutorService.submit(AbstractExecutorService.java:134) ~[na:1.8.0_161]
要分析报错的原因⾸先要指导Executor的执⾏原理是什么。
ThreadPoolTaskExecutor的⼀些参数
在配置类中配置了⼀些ThreadPoolTaskExecutor的corePoolSize核⼼线程池、maxPoolSize最⼤线程池、queneCapacity队列⼤⼩。ThreadPoolTaskExecutor会根据
corePoolSize和maxPoolSize来调整线程池⼤⼩。
当新任务执⾏时,如果运⾏的线程⼩于corePoolSize就会创建新的线程,即使其他线程是空闲状态。
如果创建的线程数量达到了corePoolSize,就会把新任务放到队列中等待执⾏。
如果队列满了,并且运⾏的线程⼩于maxPoolSize,就会创建新的线程。
如果线程达到了maxPoolSize,且队列也满了,再开启新的任务就会报错RejectedExecutionException
如果corePoolSize等于maxPoolSize,表⽰创建了固定⼤⼩的线程池。
如果设置maxPoolSize的值为Integer.MAX_VALUE表⽰创建了⽆界的线程池
队列的三种策略
直接提交
⼯作队列的默认选项是synchronousQueue,它将任务直接提交给线程⽽不保持它们。在此,如果不存在可⽤于⽴即运⾏任务的线程,则试图把任务加⼊队列将失
败,因此会构造⼀个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求⽆界maximumPoolSizes以避免拒绝新提交的任
务。当命令以超过队列所能处理的平均数连续到达时,此策略允许⽆界线程具有增加的可能性。
⽆界队列
使⽤⽆界队列(例如,不具有预定义容量的LinkedBlockingQueue)将导致在所有corePoolSize线程都忙时新任务在队列中等待。这样,创建的线程就不会超过corePoolSize(因此,maximumPoolSize的值也就⽆效了)。
有界队列
当使⽤有限的maximumPoolSizes时,有界队列(如ArrayBlockingQueue)有助于防⽌资源耗尽,但是可能较难调整和控制。队列⼤⼩和最⼤池⼤⼩可能需要相互折衷:使⽤⼤型队列和⼩型池可以最⼤限度的降低CPU使⽤率、操作系统资源和上下⽂切换开销,但是可能导致⼈⼯降低吞吐量。如果任务频繁阻塞,则系统可能为超过您许可的更多线程安排时间,使⽤⼩型队列通常要求较⼤的池⼤⼩,CPU使⽤率较⾼,但是可能遇到不可接受的调度开销,这样可会降低吞吐量。
此外,引发RejectedExecutionException的另⼀种原因是,显式的调⽤了线程池的shutdown()⽅法。
参考:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。