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

相关推荐
间彧5 小时前
Java中T类型详解与实际使用
java
凯子坚持 c5 小时前
C++ 连接 Redis:redis-plus-plus 安装与使用入门指南
java·c++·redis
没有bug.的程序员5 小时前
Redis vs Memcached vs MongoDB:深入对比与选型指南
java·redis·mongodb·memcached
易元5 小时前
模式组合应用-装饰器模式
后端·设计模式
半桔5 小时前
【Linux手册】管道通信:从内核底层原理到使用方法
java·linux·服务器·网络·c++
BeyondCode程序员5 小时前
苹果内购 V1 与 V2 支付流程对比(附示例java代码)
java·后端
叫我阿柒啊5 小时前
从全栈工程师视角解析Java与前端技术在电商场景中的应用
java· 消息队列· spring boot· 微服务· vue3· 安全· 前端框架
华仔啊5 小时前
Redis 不只是缓存!Java 打工人必知的 10 个真实工作场景,第 5 个太香了
java·后端
程序边界5 小时前
Oracle到金仓数据库信创改造迁移实施规划方案(上篇)
后端