配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.core.task.TaskExecutor;
4import org.springframework.scheduling.annotation.EnableAsync;
5import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
6
7import java.util.concurrent.ThreadPoolExecutor;
8@Configuration
9@EnableAsync
10public class ThreadPoolTaskExecutorConfig {
11
12 @Bean
13 public TaskExecutor taskExecutor() {
14 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
15 // 设置核心线程数
16 executor.setCorePoolSize(5);
17 // 设置最大线程数
18 executor.setMaxPoolSize(10);
19 // 设置队列容量
20 executor.setQueueCapacity(20);
21 // 设置线程活跃时间(秒)
22 executor.setKeepAliveSeconds(60);
23 // 设置默认线程名称
24 executor.setThreadNamePrefix("hello-");
25 // 设置拒绝策略
26 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
27 // 等待所有任务结束后再关闭线程池
28 executor.setWaitForTasksToCompleteOnShutdown(true);
29 return executor;
30 }
31}
32
模拟任务,假设每个任务大概需要耗时5S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 1@RestController
2public class Test3Controller {
3
4
5 @GetMapping("/test1")
6 public void test1() {
7 test();
8 }
9
10 @Async("taskExecutor")
11 public void test() {
12 SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
13 try {
14 Thread.sleep(5000);
15 System.out.println("多线程异步执行" + Thread.currentThread().getName() + " " + format.format(new Date()));
16 } catch (InterruptedException e) {
17 e.printStackTrace();
18 }
19 }
20}
21
启动类加入注解
1
2 1@EnableAsync
2
我们可以使用jmeter对接口进行并发压力测试【安装教程:https://blog.csdn.net/weixin_44464726/article/details/86152691】
当前线程池所能接受的最大任务数=最大线程数+队列容量
核心线程数=5
同时发送3个请求
结论:当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
同时发送8个请求
结论:.当线程池达到corePoolSize时,并且workQueue未满时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
如配置所示,
当前所配置的拒绝策略为:CallerRunsPolicy:
意思是:若当前请求超过最大任务数时,任务将被拒绝并将被直接在execute方法的调用线程中运行被拒绝的任务。
当前最大任务数为30,我给他同时发50个请求
可以看到有10个线程在我们自己定义的线程(线程名字为hello)上运行,超出最大线程数并且超出队列的20个线程直接在exec默认线程上运行了,5秒之后,10个线程任务运行完毕,从队列中获取任务去执行,知道队列中所有的任务都已经执行完成。
四种拒绝策略:
1、CallerRunsPolicy:让主线程去运行被抛弃掉的任务。好处是能够减缓新任务的提交速度。坏处是很有可能造成当前线程也被阻塞。如果所有线程都是不能执行的,很可能导致程序没法继续跑了。
2、AbortPolicy:jdk默认策略,策略直接抛出异常,丢弃任务。
3、DiscardPolicy:不能执行的任务将被删除,类似AbortPolicy,直接丢弃但不抛异常。
4、DiscardOldestPolicy:丢弃最早的未处理完的线程任务,然后获取下一个任务执行。
可自定义拒绝策略,参考:【https://blog.csdn.net/tanglei6636/article/details/90721801】