异步处理是企业开发的‘生存之道’!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、资讯、面试等多个领域。无论是前沿科技的探索,还是实用技巧的总结,我们都致力于为大家呈现有价值的内容。期待与你共同进步,开启技术之旅。

相关推荐
深盾科技_Virbox1 分钟前
云端与本地并行交付,软件许可管理如何实现统一运营?
java·大数据·开发语言·安全
thefool1122662 分钟前
多线程 3
java
Thneonl7 分钟前
别上来就 strace:60 秒十条命令看清一台病机
后端·程序员
CoderYanger8 分钟前
A.每日一题:856. 括号的分数
java·程序人生·算法·leetcode·面试·职场和发展·学习方法
马剑威(威哥爱编程)16 分钟前
【AI全栈后端12-11】Spring Boot 把 AI 接口真正上线扛量:限流 / 降级 / 可观测
人工智能·spring boot·后端
liangbo725 分钟前
01-Java 集合框架全景:从 Collection 到 Map 一张关系网理清
java
xuxigifxfh28 分钟前
HJ15 求int型正整数在内存中存储时1的个数
java·开发语言·华为机考
Wokoo731 分钟前
自动化测试入门:核心场景、回归测试与 Web 自动化环境搭建
java·开发语言·测试工具
tachibana234 分钟前
Golang 中数组和切片的区别?
开发语言·后端·golang·数组·切片
我是人✓1 小时前
Spring IOC注解全解析和Spring整合测试单元
java·后端·spring