Springboot @Async多线程获取返回值方式

 更新时间:2023年09月27日 09:21:17   作者:小白Alan  
这篇文章主要介绍了Springboot @Async多线程获取返回值方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

@Async 多线程获取返回值

最近需要用到多线程 自己维护线程池很麻烦 正好看到 springboot 集成线程池的例子 这里自己做了个尝试和总结 记录一下 也分享给需要的朋友;

不考虑事务的情况下 这个多线程实现比较简单 

主要有以下几点

  • 在启动类加上  @EnableAsync 注解, 开启异步执行支持;
  • 编写线程池配置类, 别忘了 @Configuration , 和 @Bean 注解;
  • 编写需要异步执行的业务, 放到单独的类中 (可以定义为 service, 因为需要 spring 管理起来才能用 );
  • 在业务service中调用异步执行的service, 注意这是重点, 不能直接在业务 service 中写异步执行的代码, 否则无法异步执行( 这就是单独放异步代码的原因);

好了, 上代码:

// 启动类
@EnableAsync
@EnableWebSecurity
@ServletComponentScan
@SpringBootApplication(scanBasePackages={"com.example.demo"})
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}
// 线程池配置类
@Slf4j
@Configuration
public class BootThreadpoolConfig {
    // 配置核心线程数
    private int corePoolSize = 5;
    // 配置最大线程数
    private int maxPoolSize = 20;
    // 配置任务队列的长度
    private int queueCapacity = 500;
    // 配置任务的空闲时间
    private int aliveSeconds = 600;
    // 配置线程前缀
    private String namePrefix = "localThreadPool";
    // 自定义线程池, 起个好记的名
    @Bean(name = "localBootAsyncExecutor")
    public Executor asyncServiceExecutor() {
        log.info("初始化 springboot 线程池");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix(namePrefix);
        //配置线程的空闲时间
        executor.setKeepAliveSeconds(aliveSeconds);
        // RejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
        // CallerRunsPolicy:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        log.info("springboot 线程池初始化完毕");
        return executor;
    }
}
// 异步执行代码
@Service("asyncExecutorTest")
public class AsyncExecutorTest {
    // 异步执行的方法, 注解内为自定义线程池类名
    @Async("localBootAsyncExecutor")
    public Future<Integer> test1(Integer i) throws InterruptedException {
        Thread.sleep(100);
        System.out.println("@Async 执行: " + i);
        return new AsyncResult(i);
    }
    // 这里使用其它方式调用,详见后面的 service3 方法
    public Integer test2(Integer i) throws InterruptedException {
        Thread.sleep(100);
        System.out.println(" excute.run 执行: " + i);
        return i;
    }
}
// 业务 service
@Service("asyncExcutorService")
public class AsyncExcutorService {
    @Autowired
    AsyncExecutorTest asyncExecutorTest;
    @Autowired
    Executor localBootAsyncExecutor;
    // 测试 无返回值异步执行
    public void service1(){
        System.out.println("service1 执行----->");
        for (int i = 0; i < 50; i++) {
            try {
                asyncExecutorTest.test1(i);
            } catch (InterruptedException e) {
                System.out.println("service1执行出错");
            }
        }
        System.out.println("service1 结束----->");
    }
    // 测试 有返回值异步执行
    public void service2(){
        long l = System.currentTimeMillis();
        System.out.println("service2 执行----->");
        List<Future> result = new ArrayList<>();
        try {
            for (int i = 0; i < 300; i++) {
                Future<Integer> integerFuture = asyncExecutorTest.test1(i);
                result.add(integerFuture);
            }
            for (Future future : result) {
                System.out.println(future.get());
            }
        } catch (InterruptedException | ExecutionException e) {
            System.out.println("service2执行出错");
        }
        System.out.println("service2 结束----->" + (System.currentTimeMillis() - l));
    }
    // 测试 有返回值异步执行
    public void service3(){
        long l = System.currentTimeMillis();
        List<Integer> result = new ArrayList<>();
        try {
            System.out.println("service3 执行----->");
            int total = 300;
            CountDownLatch latch = new CountDownLatch(total);
            for (int i = 0; i < total; i++) {
                final int y = i;
                localBootAsyncExecutor.execute(() -> {
                    try {
                        result.add(asyncExecutorTest.test2(y));
                    } catch (InterruptedException e) {
                        System.out.println("service3执行出错");
                    } finally {
                        latch.countDown();
                    }
                });
            }
            latch.await();
        } catch (InterruptedException e) {
            System.out.println("service3执行出错");
        }
        System.out.println("service3 结束----->" + (System.currentTimeMillis() - l));
    }
}

这里说下service1 和 service2的区别

1. 两个都用的是一个线程池执行的

2. service1 单纯执行业务, 不用返回数据, 主线程也不用等待

3. service2 需要返回数据, 主线程需要等待结果( 注意返回值只能是 Future, 最后再 .get()去获取, 否则无法异步执行)

4. service3 也可以返回数据, 但是书写上麻烦一些.  返回值直接是想要的结果, 不像 service2 还需要提取一次数据.

其它就是 controller 了, 自己随便写一个调用一下就行了, 这里就不写了, 以下是我测试的 console 日志

  • service1 执行日志

  • service2 执行日志

  • service3

总结

打完收工!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java 中很好用的数据结构EnumSet

    Java 中很好用的数据结构EnumSet

    这篇文章主要介绍了Java 中很好用的数据结构EnumSet,EnumMap即属于一个Map,下文围绕主题展开详细内容,需要的小伙伴可以参考参考一下
    2022-05-05
  • SpringMVC实现注解式权限验证的实例

    SpringMVC实现注解式权限验证的实例

    本篇文章主要介绍了SpringMVC实现注解式权限验证的实例,可以使用Spring MVC中的action拦截器来实现,具有一定的参考价值,有兴趣的可以了解下。
    2017-02-02
  • 导出maven项目依赖的jar包(图文教程)

    导出maven项目依赖的jar包(图文教程)

    下面小编就为大家带来一篇导出maven项目依赖的jar包(图文教程)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • SpringMVC自定义消息转换器的使用其实很简单

    SpringMVC自定义消息转换器的使用其实很简单

    这篇文章主要介绍了SpringMVC自定义消息转换器的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • Springboot+Mybatis实现分页加条件查询功能

    Springboot+Mybatis实现分页加条件查询功能

    这篇文章主要为大家详细介绍了Springboot+Mybatis实现分页加条件查询,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Java利用蒙特卡洛方法求解圆周率π值

    Java利用蒙特卡洛方法求解圆周率π值

    蒙特·卡罗方法(Monte Carlo method),也称统计模拟方法,是一种以概率统计理论为基础的数值计算方法。本文将利用该方法实现圆周率的计算,需要的可以参考一下
    2022-08-08
  • Java实现全排列的三种算法详解

    Java实现全排列的三种算法详解

    从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。本文总结了Java实现全排列的三种算法,需要的可以参考下
    2022-06-06
  • Java8中forEach语句循环一个List和Map

    Java8中forEach语句循环一个List和Map

    这篇文章主要给大家介绍了关于Java8中forEach语句循环一个List和Map的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • springboot 单文件上传的实现步骤

    springboot 单文件上传的实现步骤

    这篇文章主要介绍了springboot实现单文件上传的方法,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下
    2021-02-02
  • 在Java中操作Zookeeper的示例代码详解

    在Java中操作Zookeeper的示例代码详解

    这篇文章主要介绍了在Java中操作Zookeeper的示例代码详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07

最新评论