java并发学习--第二章 spring boot实现线程的创建

除了之前介绍的创建线程方式外,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);

    }
}

 

  连续请求两次测试地址,测试结果:

 

 

   

  

  

posted @ 2019-09-09 16:23  想去天空的猫  阅读(6622)  评论(2编辑  收藏  举报