Java中常用的異步方法(核心用法和場(chǎng)景)
在 Java 中,異步編程的核心目標(biāo)是避免主線程阻塞,提升程序并發(fā)性能。以下是 Java 不同版本 / 框架中最常用的異步方法,按「基礎(chǔ) API→進(jìn)階框架」的邏輯梳理,附核心用法和場(chǎng)景:
一、基礎(chǔ) JDK 異步 API(Java 5+)
1. Thread/Runnable(最基礎(chǔ))
核心邏輯:通過(guò)新建線程執(zhí)行異步任務(wù),無(wú)返回值。適用場(chǎng)景:簡(jiǎn)單異步任務(wù),無(wú)需結(jié)果、無(wú)需線程管理。
// 方式1:直接new Thread
new Thread(() -> {
// 異步執(zhí)行的任務(wù)(如IO操作、耗時(shí)計(jì)算)
System.out.println("異步任務(wù)執(zhí)行中:" + Thread.currentThread().getName());
}).start();
// 方式2:線程池(推薦,避免頻繁創(chuàng)建線程)
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> {
// 異步任務(wù)
});
// 注意:使用后需關(guān)閉線程池(優(yōu)雅關(guān)閉)
executor.shutdown();2. Future + Callable(Java 5+,支持返回值)
核心邏輯:Callable 定義有返回值的異步任務(wù),Future 接收結(jié)果,支持阻塞獲取 / 超時(shí)獲取。適用場(chǎng)景:需要異步任務(wù)返回結(jié)果,可接受阻塞等待的場(chǎng)景。
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交Callable任務(wù),返回Future
Future<String> future = executor.submit(() -> {
Thread.sleep(1000); // 模擬耗時(shí)操作
return "異步任務(wù)結(jié)果";
});
// 獲取結(jié)果(阻塞直到任務(wù)完成)
try {
String result = future.get(); // 阻塞獲取
// 或超時(shí)獲取:future.get(2, TimeUnit.SECONDS);
System.out.println("結(jié)果:" + result);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}缺點(diǎn):獲取結(jié)果時(shí)仍會(huì)阻塞,無(wú)法鏈?zhǔn)秸{(diào)用。
3. CompletableFuture(Java 8+,推薦)
核心邏輯:基于「異步回調(diào) + 流式編程」,解決 Future 阻塞問(wèn)題,支持多任務(wù)組合、異常處理、非阻塞回調(diào)。適用場(chǎng)景:復(fù)雜異步場(chǎng)景(如多任務(wù)串行 / 并行、結(jié)果聚合、異步回調(diào)),Java 8 + 首選。
核心用法:
// 1. 異步執(zhí)行無(wú)返回值任務(wù)
CompletableFuture.runAsync(() -> {
System.out.println("無(wú)返回值異步任務(wù):" + Thread.currentThread().getName());
});
// 2. 異步執(zhí)行有返回值任務(wù)(默認(rèn)使用ForkJoinPool.commonPool())
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
return "有返回值的異步結(jié)果";
});
// 3. 非阻塞回調(diào)(任務(wù)完成后處理結(jié)果)
future.thenAccept(result -> System.out.println("回調(diào)處理結(jié)果:" + result))
.exceptionally(e -> { // 異常處理
System.err.println("任務(wù)異常:" + e.getMessage());
return null;
});
// 4. 多任務(wù)組合(并行執(zhí)行后聚合結(jié)果)
CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> "任務(wù)1");
CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> "任務(wù)2");
// 等待所有任務(wù)完成,聚合結(jié)果
CompletableFuture<Void> allDone = CompletableFuture.allOf(task1, task2);
allDone.join(); // 阻塞等待所有任務(wù)完成(也可改用thenRun異步處理)
String result = task1.join() + " + " + task2.join();
System.out.println("聚合結(jié)果:" + result);
// 5. 指定自定義線程池(避免使用默認(rèn)公共池)
ExecutorService customPool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> "自定義線程池執(zhí)行", customPool)
.thenRun(() -> System.out.println("完成"))
.whenComplete((v, e) -> customPool.shutdown()); // 完成后關(guān)閉線程池二、Spring 框架中的異步方法(Spring 3+)
Spring 通過(guò)注解簡(jiǎn)化異步開(kāi)發(fā),核心是@Async。
1. 基礎(chǔ)使用(@Async)
步驟 1:開(kāi)啟異步支持(配置類(lèi) / 啟動(dòng)類(lèi))
@Configuration
@EnableAsync // 開(kāi)啟異步
public class AsyncConfig {
// 自定義線程池(可選,默認(rèn)使用SimpleAsyncTaskExecutor)
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(20);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
}步驟 2:定義異步方法
@Service
public class AsyncService {
// 無(wú)返回值異步方法
@Async
public void asyncTask() {
System.out.println("Spring異步任務(wù):" + Thread.currentThread().getName());
}
// 有返回值異步方法(返回Future/CompletableFuture)
@Async
public CompletableFuture<String> asyncTaskWithResult() {
try {
Thread.sleep(1000);
return CompletableFuture.completedFuture("Spring異步結(jié)果");
} catch (InterruptedException e) {
return CompletableFuture.failedFuture(e);
}
}
}步驟 3:調(diào)用異步方法
@Autowired
private AsyncService asyncService;
public void testAsync() {
// 調(diào)用無(wú)返回值異步方法
asyncService.asyncTask();
// 調(diào)用有返回值異步方法
CompletableFuture<String> future = asyncService.asyncTaskWithResult();
future.thenAccept(result -> System.out.println("Spring異步結(jié)果:" + result));
}2. 注意事項(xiàng)
- 異步方法不能是
private/static,且不能在同一個(gè)類(lèi)中調(diào)用(Spring AOP 代理機(jī)制); - 推薦自定義線程池,避免默認(rèn)線程池的性能問(wèn)題;
- 異常處理:可通過(guò)
@Async結(jié)合CompletableFuture捕獲異常,或自定義AsyncUncaughtExceptionHandler處理無(wú)返回值方法的異常。
三、其他常用異步場(chǎng)景
1. 異步 IO(Java NIO 2 / AIO)
適用于高并發(fā) IO 場(chǎng)景(如網(wǎng)絡(luò)通信、文件讀寫(xiě)),核心是AsynchronousFileChannel/AsynchronousSocketChannel:
// 異步文件讀取示例
Path path = Paths.get("test.txt");
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 異步讀取,通過(guò)回調(diào)處理結(jié)果
channel.read(buffer, 0, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer bytesRead, Void attachment) {
System.out.println("讀取字節(jié)數(shù):" + bytesRead);
buffer.flip();
// 處理讀取的數(shù)據(jù)
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});2. 響應(yīng)式編程(Project Reactor/Spring WebFlux)
適用于非阻塞響應(yīng)式場(chǎng)景,核心是Mono/Flux:
// 異步獲取單個(gè)結(jié)果
Mono<String> mono = Mono.fromSupplier(() -> {
Thread.sleep(1000);
return "Reactor異步結(jié)果";
}).subscribeOn(Schedulers.boundedElastic()); // 指定異步線程池
// 訂閱(觸發(fā)執(zhí)行)
mono.subscribe(result -> System.out.println("Reactor結(jié)果:" + result));四、核心選型建議
| 場(chǎng)景 | 推薦方案 |
|---|---|
| Java 8+ 簡(jiǎn)單異步 / 多任務(wù)組合 | CompletableFuture |
| Spring 項(xiàng)目中的業(yè)務(wù)異步 | @Async + 自定義線程池 |
| 高并發(fā) IO(文件 / 網(wǎng)絡(luò)) | Java AIO / Netty |
| 響應(yīng)式非阻塞系統(tǒng) | Spring WebFlux + Reactor |
| 簡(jiǎn)單無(wú)返回值異步(低并發(fā)) | Thread + 線程池 |
關(guān)鍵優(yōu)化點(diǎn):
- 所有異步場(chǎng)景都應(yīng)使用線程池(避免頻繁創(chuàng)建線程);
- 避免異步任務(wù)中的阻塞操作(如同步 IO、鎖等待),否則會(huì)耗盡線程池;
- 異步任務(wù)必須處理異常(如 CompletableFuture 的 exceptionally、Spring 的異常處理器)。
到此這篇關(guān)于Java中常用的異步方法(核心用法和場(chǎng)景)的文章就介紹到這了,更多相關(guān)java異步方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Idea 2019.2 安裝lombok插件失效問(wèn)題解決
這篇文章主要介紹了詳解Idea 2019.2 安裝lombok插件失效問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
java實(shí)現(xiàn)在原有日期時(shí)間上加幾個(gè)月或幾天
這篇文章主要介紹了java實(shí)現(xiàn)在原有日期時(shí)間上加幾個(gè)月或幾天,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
idea設(shè)置JVM運(yùn)行參數(shù)的幾種方式
對(duì)JVM運(yùn)行參數(shù)進(jìn)行修改是JVM性能調(diào)優(yōu)的重要手段,本文主要介紹了idea設(shè)置JVM運(yùn)行參數(shù)的幾種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04

