异步处理是企业开发的‘生存之道’!Java8和Spring的异步实现,你必须搞清楚!

摘要

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

差异性

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

示例代码

1)定义线程池

kotlin 复制代码
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)加上注解

kotlin 复制代码
@SpringBootApplication
public class AsyncUseApplication {...}

3)异步任务指定

typescript 复制代码
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<String> asyncMethodWithReturn(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)测试任务执行

java 复制代码
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、资讯、面试等多个领域。无论是前沿科技的探索,还是实用技巧的总结,我们都致力于为大家呈现有价值的内容。期待与你共同进步,开启技术之旅。

相关推荐
lizhongxuan19 小时前
多Agent之间的区别
后端
青石路21 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充21 小时前
1.面向对象设计思想
后端
IT_陈寒1 天前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro1 天前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗1 天前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端
她的男孩1 天前
后台接口加密别只会 HTTPS,ForgeAdmin 的 RSA + SM4/AES 源码拆解
后端·面试·开源
极光技术熊1 天前
Spring AI 从入门到精通:构建你的 AI 开发知识体系
后端·github
程序员cxuan1 天前
一句话,让你用上 GPT-5.6
人工智能·后端·程序员
远航_1 天前
OpenSpec 完整详细介绍
前端·后端