spring boot自定义线程池进行异步调用获取接口数据

spring boot自定义线程池进行异步调用

  1. 我们需要异步调用的时候,很容易就想到多线程的方式,先创建线程池,然后实现 Runnable 或者 Callable
  2. 接口来创建对象,然后将对象放在线程池中去执行。除了这个,spring 提供了更简单粗暴的方式,这就是本章的主角: @Async
  3. 如果直接使用 @Async,那么默认就是使用 SimpleAsyncTaskExecutor 线程池,由于 SimpleAsyncTaskExecutor 不限制并发线程而且不重用线程,那么直接使用是有风险的,所以需要通过自定义线程池来使用@Async 达到异步调用的目的。

1. 创建自定义线程池

@Configuration
@EnableAsync    //@EnableAsync 注解主要是为了扫描范围包下的所有 @Async 注解
public class ThreadPoolConfig {
    @Bean("taskExecutor")
    public ThreadPoolTaskExecutor taskThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setCorePoolSize(16);   //核心线程数目

        executor.setMaxPoolSize(900);   //指定最大线程数

        executor.setQueueCapacity(5);   //队列中最大的数目

        executor.setThreadNamePrefix("defaultThreadPool_"); //线程名称前缀
        //rejection-policy:当pool已经达到max size的时候,如何处理新任务
        //CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());    //对拒绝task的处理策略

        executor.setKeepAliveSeconds(60);  //线程空闲后的最大存活时间

        executor.initialize();  //加载
        return executor;
    }
}

2.创建异步任务类(service 层)


@Service
public class ThreadPoolServiceImpl {
    // task 1
    @Async("taskExecutor")
    public void Asynctask1() {
        System.out.println("task1 开始执行");
        long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(500L);
            Asynctask2();
            System.out.println("运行成功,task1的线程是"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("出错了!task1的线程是"+Thread.currentThread().getName());
        }
        System.out.println("test 执行结束,耗时:" + (System.currentTimeMillis() - startTime));
    }
    // task 2
    @Async("taskExecutor")
    public void Asynctask2() {
        System.out.println("task2 开始执行");
        long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(500L);
            System.out.println("运行成功,task2的线程是"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("出错了!task2的线程是"+Thread.currentThread().getName());
        }
        System.out.println("test 执行结束,耗时:" + (System.currentTimeMillis() - startTime));
    }
}

3.接口调用类(controller 层)

@RestController
public class ThreadPoolController {
    @Autowired
    private ThreadPoolServiceImpl threadPoolService;

    @Async("taskExecutor")
    @ResponseBody
    @RequestMapping(value = "/test1", method = RequestMethod.GET)
    public String threadPooltest1() {
        System.out.println("test 开始执行");
        threadPoolService.Asynctask1();
        return "运行成功threadPooltest1";
    }

    @Async("taskExecutor")
    @ResponseBody
    @RequestMapping(value = "/test2", method = RequestMethod.GET)
    public String threadPooltest2() {
        System.out.println("test 开始执行");
        threadPoolService.Asynctask1();
        threadPoolService.Asynctask2();
        return "运行成功threadPooltest2";
    }
}

3.1 运行结果:

在这里插入图片描述

4.有返回值的异步任务

以上的 task1 和 task2 任务是没有返回值,如果碰到需要获取任务结果就要用到 Future 了。

4.1 service 层:

@Service
public class ThreadPoolServiceImpl {
    // task 3
    @Async("taskExecutor")
    public Future<String>  Asynctask3() throws Exception{
        System.out.println("task3线程名称:" + Thread.currentThread().getName());
        long startTime = System.currentTimeMillis();
//        int i=8/0;
        Thread.sleep(1000);
        System.out.println("test3 执行结束,耗时:" + (System.currentTimeMillis() - startTime));
        return new AsyncResult<>("成功");
    }
}

4.2 controller 层:


@RestController
public class ThreadPoolController {
    @Autowired
    private ThreadPoolServiceImpl threadPoolService;

    @Async("taskExecutor")
    @ResponseBody
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String threadPooltest3() throws Exception {
        System.out.println("test 开始执行");
        System.out.println("threadPooltest3此时正在运行的线程名称:" + Thread.currentThread().getName());
        try {
            Future<String> stringFuture = threadPoolService.Asynctask3();
            System.out.println("threadPooltest3此时正在运行的线程名称:" + Thread.currentThread().getName());
            System.out.println(stringFuture.get());
            return "成功了"+stringFuture.get();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("出错了");
            return "出错了";
        }
    }
}

4.3 调试接口:

在这里插入图片描述

可以明显看出,task1 和 task2 不是异步执行的。原因就是调用 task1 和 task2 方法的是 AsyncTask 对象本身,而不是 spring 启动的时候为其创建的代理对象,没有经过 spring 容器。如果要解决这个问题,就按照这个思路,创建一个代理对象即可。

5.真正的异步调用

在 service 中先通过自动装配获取 applicationContext 对象,然后通过 applicationContext 获取 AsyncTask 的代理对象,通过代理对象来调用 task1 和 task2 :

@Component
public class ThreadPoolServiceImpl {

    @Autowired
    private ApplicationContext applicationContext;


    public void test(){
        System.out.println("test 开始执行");
        long startTime = System.currentTimeMillis();
        applicationContext.getBean(ThreadPoolServiceImpl.class).task1();
        applicationContext.getBean(ThreadPoolServiceImpl.class).task2();
        System.out.println("test 执行结束,耗时:" + (System.currentTimeMillis() - startTime));
    }

    /**
     * task 1
     */
    @Async("taskExecutor")
    public Future<String> task1() {
        System.out.println("task1 开始执行");
        long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
        }
        System.out.println("task1 执行结束,耗时:" + (System.currentTimeMillis() - startTime));
        return new AsyncResult<>("task1 success");
    }

    /**
     * task 2
     */
    @Async("taskExecutor")
    public Future<String> task2() {
        System.out.println("task2 开始执行");
        long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
        }
        System.out.println("task2 执行结束,耗时:" + (System.currentTimeMillis() - startTime));
        return new AsyncResult<>("task2 success");
    }
}

调用方法:

@GetMapping("/async")
public void test() throws ExecutionException, InterruptedException {
    System.out.println("test 开始执行");
    asyncTask.test();
    long startTime = System.currentTimeMillis();
    System.out.println("test 执行结束,耗时:" + (System.currentTimeMillis() - startTime));
}

👉点击领取源代码:

提取码:2b9w

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值