深入理解同步和异步、阻塞和非阻塞、并行和串行这几个概念

2022-02-15 08:18:41 浏览数 (1)

一、背景

晚上技术群里有朋友问,“同步和阻塞色区别是什么?”

有不少朋友给出去了自己的看法,部分内容如下:

其中有朋友给出了截图,图上给出了比较“生动”的例子。

然而,看完之后似乎懂了,似乎又没懂。

很多人对这几个常见的概念,似乎熟悉而又陌生。

二、理解

2.1 前缘

如果之前有同学看过我的 《我眼中的Java大牛之孤尽老师》 这篇文章,就会发现里面已经提及一二,遗憾的是大多数同学都是遇到问题的时候才想着去问去看。

2.2 视角

对于这个问题,我更倾向于大家以视角的思维去看。

同步和异步是函数调用视角

即同步执行函数调用后,必须等待函数返回才能继续执行;异步则不需要等待返回即可继续执行其他任务。

比如领导安排你去打印一本几百页的电子书,同步的话相当于你自己亲自去打印,打印时一直在打印机器边上等待打印完成,再去干其他事情;异步的话我们点击完打印之后就去干其他事情,如点击打印之后先去刷个剧或者我们请另外一个同学帮我们打印,然后自己去干其他事情。

回到具体业务上来,假设我们需要在系统登录成功之后给用户发短信通知,我们在登录完毕之后,使用线程池起线程或者发送消息队列消息通知下游去执行短信发送,登录方法不必等发送短信程序执行完毕就可以直接返回。

阻塞和非阻塞是线程视角

在我看来,阻塞和非阻塞是描述线程状态。 所谓阻塞是指执行某个调用后当前线程被挂起(如生产消费者模型中,无消费内容时 wait),释放CPU ,直到等得到结果被唤醒(有可消费内容时 通过 notifyAll 唤醒消费线程);非阻塞是指执行某个调用后,即使不能立刻得到结果,当前线程也不会被挂起。

比如出租车司机,接到乘客之后,前面的牌子就要翻到 有人,此时无法继续接客,知道乘客下车结束订单,这就是阻塞;出租车司机接到乘客后不将牌子翻到有人,即使当前一个乘客没有送到目的地,还可以继续接单,则就是非阻塞。

通常阻塞会造成线程进入挂起状态(效果如调用了 wait 方法),同步调用时线程还是运行状态,正在执行函数调用(效果如调用了 sleep 方法),只不过调用还没有返回。

并行和串行是 CPU 视角

并行任务通常可以拆分成多个步骤,多个CPU 核心一起执行,这类任务之间通常没有依赖关系,完全正交;串行任务每一个步骤同时只能有一个核心执行,通常有上下游依赖关系。

我们可以将多个人比喻为多个CPU核心。比如我们想把大象装冰箱里,就要先打开 冰箱门,然后把大象装进去,然后再关上冰箱门,即使我们有多个人,但是步骤不能同时执行。即不能冰箱门还没打开就直接装大象,也不能大象还没进去就直接关闭冰箱门,这就是串行。

我们如果想出版一本书,可以将书拆分成不同的章节,然后每人分一个章节,大家一起写,此时在时间上多人是在一起做任务,而且对进度都有帮助,这就是并行。

沿用这个例子,我们想下并行 和 并发 的区别,并发相当有我们只有一个人,可以一会写第一章,一会写第二章,一会写第三章,然后再写第一章等,虽然可以切换做不同的事情,但是只有一个人。

三、总结

对于这几个概念,希望大家能够抓住本质,而不要被各种例子所迷惑。

同步和异步是函数调用视角,判断依据是调用之后是否需要等待返回

阻塞和非阻塞是线程视角,即调用之后当前线程是否被挂起

并行和串行是 CPU 视角,即是否同时有多核一起承担同一项任务。

本文只是谈谈自己的理解,如果有疏漏,大家可以评论和我交流,也欢迎大家给出更通俗易懂的理解方式。

创作不易,如果本文对你有帮助,欢迎点赞、收藏加关注,你的支持和鼓励,是我创作的最大动力。

0 人点赞