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