除了之前介绍的创建线程方式外,spring boot为我们了提供一套完整的线程创建方式,其中包括了:线程、线程池、线程的监控。
一、使用spring boot提供的方法创建线程与线程池
1.首先在spring boot 的启动类上加上注解:@EnableAsync
//开启异步线程必须加上注解
@EnableAsync @SpringBootApplication public class ThemApplication { public static void main(String[] args) { SpringApplication.run(ThemApplication.class, args); } }
2.spring boot创建的线程,需要我们先创建线程池
/** * 线程池的配置 * * 需要加上这两个注解 */ @Configuration @EnableAsync public class Pool implements AsyncConfigurer { @Bean("thread") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 设置核心线程数
executor.setCorePoolSize(5); // 设置最大线程数
executor.setMaxPoolSize(10); // 设置队列容量
executor.setQueueCapacity(20); // 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60); // 设置线程名称
executor.setThreadNamePrefix("hello-"); // 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
3.不带返回值的线程任务创建,线程任务创建很方便,只需要在线程方法使用@Async注解就行,并且把这个类交给spring来管理
@Configuration public class UseTask { @Async public void show(int i) { System.out.println("线程" +i + " 执行异步任务:" ); } }
测试的结果:
4.带返回值的线程任务创建
带返回值的线程需要实现Future<T>方法,T表示返回的类型
@Configuration public class UseTask { //带返回值的线程
@Async public Future<Integer> showSum(int i,int j) { int x=i+j; System.out.println("当前执行的是第"+i+"线程"); return new AsyncResult<Integer>(x); } }
可以看到这个方法返回的是一个Future<Integer>,所以我们要通过这个类中的get方法获取返回值
@Test public void thread() throws ExecutionException, InterruptedException { int j = 0; for (int i = 0; i < 10; i++) { //返回的类型 Future<Integer> num = useTask.showSum(i, i); //get方法获取返回值 j = num.get(); System.out.println("计算结果是" + j); } }
二、spring boot线程池的监控
springboot中监控线程的操作非常简便,只需要继承ThreadPoolTaskExecutor类就能实现
/** * 监控线程的类很简单,只需要继承ThreadPoolTaskExecutor * */ @Configuration public class Monitor extends ThreadPoolTaskExecutor { /** * 创建一个线程安全的ConcurrentHashMap,存储监控的信息 */
public ConcurrentHashMap<String, ThreadPoolTaskExecutor> threadPoolMap = new ConcurrentHashMap<>(); }
监控类创建好后,还需要在线程池配置中声明。修改后的pool类
/** * 线程池的配置 * * 需要加上这两个注解 */ @Configuration @EnableAsync public class Pool implements AsyncConfigurer { @Autowired Monitor monitor; @Bean("thread") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 设置核心线程数
executor.setCorePoolSize(5); // 设置最大线程数
executor.setMaxPoolSize(10); // 设置队列容量
executor.setQueueCapacity(20); // 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60); // 设置线程名称
executor.setThreadNamePrefix("hello-"); // 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true); //配置线程池到线程监控类中,第一个参数为线程池的名称
monitor.threadPoolMap.put("thread", executor); return executor; } }
编写测试类,获取线程的监控数据
@RestController public class Test { @Autowired UseTask useTask; @Autowired Monitor monitor; @RequestMapping(value="/test",method= RequestMethod.GET) public void meetInitMain() throws InterruptedException { //线程任务的创建
useTask.show(1); useTask.show(2); useTask.show(3); useTask.show(4); useTask.show(5); //获取监控的信息,从threadPoolMap中得到在线程池配置类中put进去的线程池名称
ThreadPoolTaskExecutor monitorTask = monitor.threadPoolMap.get("thread"); //threadPoolExecutor才是线程监控的信息存储类
ThreadPoolExecutor threadPoolExecutor= monitorTask.getThreadPoolExecutor(); //当前线程池中的工作线程数
int poolSize=threadPoolExecutor.getPoolSize(); //队列中的任务
int queueSize=threadPoolExecutor.getQueue().size(); //线程正在执行的任务
int activeCount=threadPoolExecutor.getActiveCount(); //已经执行完成的任务
Long completedTaskCount=threadPoolExecutor.getCompletedTaskCount(); //全部的任务数
Long taskCount=threadPoolExecutor.getTaskCount(); //线程池中曾经最大的线程数量
int largestPoolSize= threadPoolExecutor.getLargestPoolSize(); Thread.sleep(100); System.out.println("当前线程池中的工作线程数:"+poolSize+" 队列中的任务有:"
+queueSize+" 正在执行的任务:"+activeCount +" 已经执行完成的任务:"+completedTaskCount+" 全部的任务数:"+taskCount +"线程池中曾经最大的线程数量:"+largestPoolSize); } }
连续请求两次测试地址,测试结果: