一、什么是同步?
先简单画一个图再解释:
我打算做番茄炒蛋,于是我去街上买点西红柿买点鸡蛋然后拿回家做。
假设我的步骤如下:
- 买西红柿
- 买鸡蛋
- 炒鸡蛋
- 炒西红柿
这就是我的操作顺序,所以–>
同步: 在同一个时间点我只能干一样事情,我只能一件干完再去干下一件事。
public class 同步 {
public static void main(String[] args) {
int i = 1;
i = 买西红柿(i);
i = 买鸡蛋(i);
i = 炒鸡蛋(i);
i = 炒西红柿(i);
System.out.println("做好啦!");
}
private static int 买西红柿(int i) {
System.out.println("第" + (i++) + "步:我去买西红柿了");
return i;
}
private static int 买鸡蛋(int i) {
System.out.println("第" + (i++) + "步:我去买鸡蛋了");
return i;
}
private static int 炒鸡蛋(int i) {
System.out.println("第" + (i++) + "步:我去炒鸡蛋了");
return i;
}
private static int 炒西红柿(int i) {
System.out.println("第" + (i++) + "步:我去炒西红柿了");
return i;
}
}
二、什么是异步?
还是先画图再解释
小李:我去买西红柿炒西红柿,小张你呢去买点鸡蛋炒一下再给我,然后我再西红柿鸡蛋一起炒。
小张买鸡蛋和小李买西红柿有关系吗?没有关系,他俩是异步的
小张买鸡蛋和小张炒鸡蛋有关系吗?有关系,他俩是同步的
小张炒鸡蛋和小李番茄炒蛋有关系吗?有关系,小李要得到鸡蛋才能番茄炒蛋,他俩是同步的
小张可以做自己的事情,同时小李也可以做自己的事情,这就是异步。
测试代码:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class 异步 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
for(int i = 0;i<10;i++) {
做饭();
System.out.println("=================");
}
}
public static void 做饭() throws InterruptedException, ExecutionException {
CompletableFuture<Boolean> 小张你要做的事情 = CompletableFuture.supplyAsync(() -> {
try {
买鸡蛋();
return 炒鸡蛋();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
return false;
});
买西红柿();
炒西红柿();
if (小张你要做的事情.get()) {
番茄炒蛋();
}
}
private static void 买西红柿() throws InterruptedException {
System.out.println(System.currentTimeMillis() + ":我去买西红柿了");
Thread.sleep(1000);
}
private static void 买鸡蛋() throws InterruptedException {
System.out.println(System.currentTimeMillis() + ":我去买鸡蛋了");
Thread.sleep(1000);
}
private static boolean 炒鸡蛋() throws InterruptedException {
System.out.println(System.currentTimeMillis() + ":我去炒鸡蛋了");
Thread.sleep(1000);
return true;
}
private static void 炒西红柿() throws InterruptedException {
System.out.println(System.currentTimeMillis() + ":我去炒西红柿了");
Thread.sleep(1000);
}
private static void 番茄炒蛋() throws InterruptedException {
System.out.println(System.currentTimeMillis() + ":番茄鸡蛋一起炒");
Thread.sleep(1000);
}
}
买西红柿一定在炒西红柿前面,有先后顺序,同步
买鸡蛋一定在炒鸡蛋前面,有先后顺序,同步
买西红柿不一定在买鸡蛋前面,无先后顺序,不需要等待另一个完成,异步
炒西红柿不一定在炒鸡蛋前面,无先后顺序,不需要等待另一个完成,异步
上述四个一定在番茄炒蛋前面,有先后顺序,必须等待上面的完成,同步
什么是阻塞?
有这样一条河流,本来挺顺畅的一泻千里,突然来了块大石头矗立在河流中央,水流无法正常通过了,这就是阻塞。
河道就比方我们的CPU,水流就是线程,出现大石头阻塞了,水流等待(线程挂起)
阻塞之后河道(CPU)还在,但水流(线程)没了,河道(CPU)是不是闲着。
同样,假设咱们有1000个线程,都要执行这个逻辑,你在这阻塞着,这1000个线程是不是很快都挂起了,这样任务没处理掉,cpu还闲着没事干。
所以我们有了非阻塞,不能让你CPU闲着,该干活还要给我干活
万恶的资本家
什么是非阻塞?
非阻塞就是,前方有大石头了,你也直接给我过掉,返回一个值,让我知道你失败了,我轮询下一个,这样CPU利用率就相对来说高一些了。
Java的发展历程其实就是不断的发现问题然后解决问题的过程,非阻塞性能就好了吗?其实也不然,非阻塞采用轮询的方式,就浪费了CPU时间片,性能依然不好。
那怎么才能同时检测多个,还不浪费CPU时间片呢,这个就有一个新的东西出来了,叫IO多路复用,这个下次再写。
总结
同步、异步 和 阻塞、非阻塞 个人感觉角度不一样。
同步:线程主动的等待结果
阻塞:线程被动的等待结果
异步:线程直接忙别的,不管了或者等待回调然后才继续
非阻塞:线程忙别的,时不时的过来瞅瞅好了没
纯属个人理解,如果有不对的地方,欢迎大家指正呀😀