Java 如何做异步

很多上班族应该都有过同时做几件事的经历:煮上粥的同时,收拾餐桌、准备上班用的文件,不用等粥煮好再做别的,这样效率高很多。写代码也是一样,如果一件事可以拆分出来慢慢做,不用等它结束再处理后续,就能节省不少时间。Java里的“异步”,就是帮代码实现这种“不用等”的工具,今天就用生活化的例子讲清楚它的用法。

最基础的异步:用线程分开做

刚学Java的人,最容易想到的异步方式就是开新线程。比如你要做两件事:下载一份大报告,同时整理桌面文件。如果用同步的写法,得等报告下载完,才能开始整理,总时间是“下载时间+整理时间”。但用异步的话,把下载报告的任务交给另一个线程,主线程直接去整理文件,总时间就变成“下载时间”和“整理时间”里更长的那个,效率一下就提上来了。

Java 如何做异步

举个实际的代码小例子,用最原始的线程写法:

`java

// 主线程做整理文件的事

new Thread(() -> {

// 另一个线程做下载报告的事

System.out.println("开始下载报告,大概需要5秒");

try {

Thread.sleep(5000); // 模拟下载耗时

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("报告下载完成,可以开始处理了");

}).start();

System.out.println("现在就去整理桌面文件,大概需要3秒");

try {

Thread.sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("桌面整理好了");

`

运行这段代码,你会看到“整理桌面文件”先打印,“下载报告”后打印,不用等下载完再整理,这就是最基础的异步效果。不过这种方式有个小问题:如果要管理多个异步任务,比如同时下载3份报告,手动开线程就会很乱,还可能浪费资源。

更省心的异步:用CompletableFuture

后来Java出了CompletableFuture,就像给你配了个“任务小秘书”,能同时管理好几个异步任务,还能在任务完成后自动处理后续步骤,不用自己盯着。还是用刚才的例子,现在要同时下载报告和收集客户信息,等两个都完成后,再把内容合并起来。

用CompletableFuture的写法是这样的:

`java

// 异步下载报告

CompletableFuture<String> downloadReport = CompletableFuture.supplyAsync(() -> {

System.out.println("正在下载报告");

try { Thread.sleep(5000); } catch (InterruptedException e) {}

return "2024年度销售报告";

});

// 异步收集客户信息

CompletableFuture<String> getClientInfo = CompletableFuture.supplyAsync(() -> {

System.out.println("正在收集客户信息");

try { Thread.sleep(3000); } catch (InterruptedException e) {}

return "10位核心客户信息";

});

// 两个任务都完成后,自动合并内容

CompletableFuture<String> mergeTask = downloadReport.thenCombine(getClientInfo, (report, info) -> {

return report + " + " + info;

});

// 最终结果

System.out.println("合并后的内容:" + mergeTask.get());

`

这个写法里,“小秘书”会同时安排下载和收集,等两个都结束后自动合并,不用你手动等每个任务。要是其中一个任务出错,比如下载报告失败,它还能自动处理,不用整个流程卡住,比手动开线程省心多了。

专业场景的异步:线程池兜底

不管是手动开线程还是CompletableFuture,都需要用到“线程池”,它就像一个固定大小的员工队伍,不会每次都新招临时工(新开线程),避免资源浪费。比如你要同时处理10个异步任务,线程池就安排10个员工一起做,要是只有5个员工,就排队等,不会让电脑因为开太多线程变卡。

举个简单的线程池例子,给CompletableFuture配个线程池:

`java

// 创建一个固定有5个员工的线程池

ExecutorService pool = Executors.newFixedThreadPool(5);

// 用这个线程池做异步任务

CompletableFuture.supplyAsync(() -> {

// 异步任务内容

}, pool);

`

这样就不用每次自己管线程的数量,专业场景里都会用线程池来管理异步任务,避免出问题。

总结一下,Java做异步没有什么复杂的黑科技,就是把“不用等的事”交给单独的线程处理,从最基础的手动开线程,到用CompletableFuture管理多个任务,再用线程池兜底,根据自己的需求选就行。小任务用简单的方式就够,多任务、复杂流程就用CompletableFuture,就能写出效率更高的代码。

上一篇 C / C++ 编程语言的核心特性与经典应用场景科普