概述
何为异步?
在了解这个问题之前 先来看看什么是同步。
线程发出一个请求,在这个请求的相应没回来之前,此线程啥也不能做,只能等着。
就好比你去食堂吃饭,要排队。
再来看异步:
线程发出一个请求,该请求会进去消息队列去替线程排队,该线程可以继续处理其他事情。
就好比你去银行办理业务,去了先取号,号替你排队。
显然,异步看起来效率更高。
同步的作用,在保证业务逻辑正确性的同时,也限制了执行效率。
- 这一点没什么不对,因为逻辑不对,程序效率再高又有什么意义呢?
但,有时候同步的限制力度会超出业务逻辑本身。
我们要做的,就是 最大程度的异步 和 最精准的同步。
场景1——不需要返回值的
一些不需要返回值的请求,自然可以达到完全异步。
给个例子感受一下:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class Future_Demo_0 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("runAsync");
});
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main");
long end = System.currentTimeMillis();
System.out.println("time:"+(end-start));
}
}
结果:
main
time:1056
runAsync
在主线程和子线程里 我们都让其休眠了一秒钟,但从结果看来,主 、子 线程应该是一块儿休眠的。各睡各的,并行操作(多CPU核下)。
场景2——需要借助响应的
主线程需要得到子线程的处理结果才能继续完成某个事情。
同样给个例子帮助治疗一下:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class FutureDemo_1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "supplyAsync";
});
System.out.println("模拟其他任务1——start...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("模拟其他任务1——end...");
if (!future.isDone()){//判断异步任务是否执行完毕
System.out.println("异步任务还没完成,不能执行异步任务,请耐心等待...");
}
System.out.println("获得异步任务返回值: "+future.get());//get 方法会阻塞
System.out.println("异步任务返回值到位,开始执行依赖任务——start...");
TimeUnit.SECONDS.sleep(1);
System.out.println("异步任务返回值到位,完成执行依赖任务——end...");
long end = System.currentTimeMillis();
System.out.println("time:"+(end-start));
}
}
结果:
模拟其他任务1——start…
模拟其他任务1——end…
异步任务还没完成,不能执行异步任务,请耐心等待…
获得异步任务返回值: supplyAsync
异步任务返回值到位,开始执行依赖任务——start…
异步任务返回值到位,完成执行依赖任务——end…
time:4045
上述情况:按同步的处理思想的话:异步任务3秒 任务一1秒 依赖任务 2秒。
一共要花费 6 秒才行。
这里只花费了4秒。
其实像这样的简单业务用 Thread.yield(); 也能实现,但如果业务比较复杂的话,可能就有点窒息了。