众所周知,创建显示线程和直接使用未配置的线程池创建线程,都会被阿里的大佬给diss,所以我们要规范的创建线程。
至于 @Async 异步任务的用处是不想等待方法执行完就返回结果,提高软件前台响应速度,一个程序中会用到很多异步方法,所以需要使用线程池管理,防止影响性能。
需要一个Springboot项目
也可以自己new一个ThreadPoolExecutor自定义参数
参数说明:
阻塞队列的实现类:
处理策略Handler:
线程池的关闭:
shutdown() : 不会立刻终止线程,等所有缓存队列中的任务都执行完毕后才会终止。
shutdownNow() : 立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
package com.xuyijie.threadpooldemo.config; import org.springframework.boot.SpringBootConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.*; /** * @author 徐一杰 * @date 2022/9/20 13:05 * @description 配置线程池 */ @SpringBootConfiguration @EnableAsync public class ThreadPoolConfig { @Bean public ExecutorService getThreadPool(){ ExecutorService threadPool = new ThreadPoolExecutor(2,5, 1L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); return threadPool; // return Executors.newCachedThreadPool(); } /** * 下面的配置是配置Springboot的@Async注解所用的线程池 */ @Bean public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //获取到cpu内核数 int i = Runtime.getRuntime().availableProcessors(); // 设置线程池核心容量 executor.setCorePoolSize(i); // 设置线程池最大容量 executor.setMaxPoolSize(i * 2); // 设置任务队列长度 executor.setQueueCapacity(200); // 设置线程超时时间 executor.setKeepAliveSeconds(60); // 设置线程名称前缀 executor.setThreadNamePrefix("xyjAsyncPool-"); // 设置任务丢弃后的处理策略,当poolSize已达到maxPoolSize,如何处理新任务(是拒绝还是交由其它线程处理),CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }
使用此线程池时直接注入ExecutorService,然后:
executorService.execute(() -> { try { String message = redisUtil.listRightPop(“queue:queueData”, 5, TimeUnit.SECONDS); System.out.println(“接收到了消息message” + message); } catch (Exception ex) { date.set(simpleDateFormat.format(new Date())); System.out.println(“队列阻塞超时-” + date + ex.getMessage()); } finally { date.set(simpleDateFormat.format(new Date())); System.out.println(“线程销毁-” + date); executorService.shutdown(); } });
package com.xuyijie.threadpooldemo.controller; import com.xuyijie.threadpooldemo.async.AsyncMethod; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.ExecutorService; /** * @author 徐一杰 * @date 2022/9/20 10:30 * @description */ @RestController @RequestMapping("/test") public class TestController { @Autowired private ExecutorService executorService; @Autowired private AsyncMethod asyncMethod; @GetMapping("/helloThread") public void helloThread(){ executorService.execute(() -> { for (int i = 0;i < 100;i++){ System.out.println("111"); } }); executorService.execute(() -> { for (int i = 0;i < 100;i++){ System.out.println("222"); } }); } @GetMapping("/helloAsync") public String helloAsync(){ // 这个方法是异步的 asyncMethod.print(); System.out.println("print方法还在循环,但我已经可以执行了"); return "print方法还在循环,但我已经可以执行了"; } }
AsyncMethod.java
package com.xuyijie.threadpooldemo.async; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; /** * @author 徐一杰 * @date 2022/9/20 15:10 * @description 异步方法 */ @Component public class AsyncMethod { /** * 异步方法,如果@Async加在类的上面,则整个类中的方法都是异步的 */ @Async public void print(){ for (int i = 0;i < 100;i++){ System.out.println(i); } } }
首先演示 helloThread 这个接口,创建了2个线程,发现他们并发执行,成功
再演示 helloAsync 这个接口,发现 System.out.println("print方法还在循环,但我已经可以执行了");
这行代码无需等待上面AsyncMethod中的 print 方法执行完毕,就可以开始执行,说明 print 方法是异步的,而且我输出的日志注意看,[xyjAsyncPool - ]
,我设置的线程池前缀,已经生效了,成功