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

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

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  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 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));
    }

    
    @Async("taskExecutor")
    public Future 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");
    }

    
    @Async("taskExecutor")
    public Future 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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4668100.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-06
下一篇 2022-11-06

发表评论

登录后才能评论

评论列表(0条)

保存