摘要

本文介绍Java8和Spring处理异步的两种方式。

差异性

特性CompletableFuture.supplyAsync()@Async
依赖Java8自带依赖Spring
线程池管理可显式指定线程池可通过@Async("线程池别名")指定
异步处理exceptionally手动try-catch
事务支持默认不支持可结合@Transactional
注意事项需手动写代码进行异步任务等待启动类需加上@EnableAsync

示例代码

1)定义线程池

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class AsyncConfig {

    @Bean(name = "taskExecutor")
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // 核心线程数
        executor.setMaxPoolSize(10);  // 最大线程数
        executor.setQueueCapacity(100); // 队列容量
        executor.setThreadNamePrefix("Async-"); // 线程名前缀
        executor.initialize();
        return executor;
    }
}

2)加上注解

@SpringBootApplication
public class AsyncUseApplication {...}

3)异步任务指定

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
public class AsyncService {

    //如果不指定线程池,CompletableFuture.supplyAsync默认使用ForkJoinPool.commonPool()
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    // 无返回值的异步方法
    @Async("taskExecutor"// 指定线程池名称
//    @Transactional(rollbackFor = Exception.class) //可结合事务
    public void asyncMethodWithoutReturn(String param) {
        try {
            log.info("异步方法块开启: " + param);
            Thread.sleep(11000); // 模拟耗时操作
        } catch (Exception e) {
            log.error("出现异常:" + e.getMessage());
        }
    }

    // 有返回值的异步方法
    @Async("taskExecutor"// 指定线程池名称
    public CompletableFuture<StringasyncMethodWithReturn(String param) {
        log.info("异步方法块开启: " + param);
        try {
            Thread.sleep(11000); // 模拟耗时操作
        } catch (Exception e) {
            log.error("出现异常:" + e.getMessage());
        }
        return CompletableFuture.completedFuture("返回结果");
    }

    // 直接使用Java 8的CompletableFuture
    public void doAsync() {
        //异步执行任务
        CompletableFuture.supplyAsync(() -> {
            try {
                //执行逻辑
                log.info("异步方法块执行");
                Thread.sleep(110000); // 模拟耗时操作
            } catch (Exception e) {
                log.error("出现异常:" + e.getMessage());
            }
            return "1";
        }, threadPoolTaskExecutor)
        //异常捕获
        .exceptionally(ex -> {
            log.error("异步任务异常:" + ex.getMessage());
            return "默认值"// 返回默认值或处理异常
        });
        //或者处理异步结果
//        .thenAccept(result -> {
//            log.info("异步任务结果:" + result);
//        });
    }
}

4)测试任务执行

import lombok.extern.slf4j.Slf4j;
import org.coffeebeans.service.AsyncService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * <li>ClassName: org.org.coffeebeans.AsyncTest </li>
 * <li>Author: OakWang </li>
 */
@Slf4j
@SpringBootTest
public class AsyncTest {

    // 以下如果用sout来测试,可能会有异步顺序不对问题
    // 因为Java的System.out.println使用行缓冲:输出内容会被缓存在内存中,直到遇到换行符(n)或程序结束时才会刷新到控制台。
    @Autowired
    private AsyncService asyncService;

    @Test
    void test1() throws InterruptedException {
       asyncService.asyncMethodWithoutReturn("测试");
       log.info("111");
       /*
          2025-08-31 16:11:55.454  INFO 19860 --- [           main] org.coffeebeans.AsyncTest                : 111
          2025-08-31 16:11:55.459  INFO 19860 --- [        Async-1] org.coffeebeans.service.AsyncService     : 异步方法块开启: 测试
        */
    }

    @Test
    void test2() throws ExecutionException, InterruptedException {
       CompletableFuture<String> future = asyncService.asyncMethodWithReturn("测试");
       log.info("111");
       log.info("异步执行返回: " + future.get());
       /*
          2025-08-31 16:10:01.082  INFO 12700 --- [           main] org.coffeebeans.AsyncTest                : 111
          2025-08-31 16:10:01.088  INFO 12700 --- [        Async-1] org.coffeebeans.service.AsyncService     : 异步方法块开启: 测试
          2025-08-31 16:10:12.094  INFO 12700 --- [           main] org.coffeebeans.AsyncTest                : 异步执行返回: 返回结果
        */
    }

    @Test
    void test3() {
       asyncService.doAsync();
       log.info("111");
       /*
          2025-08-31 16:11:14.924 INFO 17944 --- [           main] org.coffeebeans.AsyncTest                : 111
          2025-08-31 16:11:14.924 INFO 17944 --- [        Async-1] org.coffeebeans.service.AsyncService     : 异步方法块执行
        */
    }

}

总结

以上我们了解了Java8和Spring处理异步的两种方式,有各自的好,对应Spring项目示场景而定,可以混用,但需要注意线程池的管控。

关注公众号:咖啡Beans

在这里,我们专注于软件技术的交流与成长,分享开发心得与笔记,涵盖编程、AI、资讯、面试等多个领域。无论是前沿科技的探索,还是实用技巧的总结,我们都致力于为大家呈现有价值的内容。期待与你共同进步,开启技术之旅。

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]