理解 同步/ 异步 与 阻塞/非阻塞

在学习 JavaScript 过程中,经常遇到 同步/异步 ,阻塞/非阻塞 ,的说法,以前对其只有基本概念上的认识,对其机制存在困惑,比如到底什么是阻塞和非阻塞?什么是同步和异步?同步就一定是阻塞吗?异步就一定是非阻塞吗?
最近在学习 Node.js 过程中对这些概念有了更深的理解。

我们先来看一个例子,再去理解分辨这些概念。

(一)爱喝茶的老张

老张没别的爱好,就是爱喝茶,喝茶首先要烧开水。
出场人物:老张
出场道具:普通水壶(简称水壶);烧开水会鸣笛的水壶(简称响水壶)

  1. 老张把水壶放到火上,然后就站在旁边等着水开。这是 同步阻塞
  2. 老张把水壶放到火上,然后去客厅看电视,时不时来看一眼水有没有开。这是 同步非阻塞
  3. 老张把响水壶放到火上,然后站在旁边等着水开。这是 异步阻塞
  4. 老张把响水壶放到火上,然后觉得既然水开了会响,那还站在这有点太傻了,于是去客厅看电视了。这是 异步非阻塞

(二)阻塞和非阻塞

阻塞和非阻塞描述的是一种 状态,在上面的例子中,阻塞还是非阻塞的判断条件就是烧水时老张的状态,可以去做其他事情(看电视)就是非阻塞,在水壶旁边干等着无法去做其他事情就是阻塞。

用书面化一点的语言来说,就是

阻塞和非阻塞关注的是在等待调用结果时的状态

  1. 阻塞是指在调用结果返回之前,当前线程会被挂起,调用线程只有在得到结果之后才返回
  2. 非阻塞是指在调用不能立刻返回结果时,该调用不会阻塞当前线程

(三)同步和异步

同步和异步描述的是一种 消息通知方式 ,在上面的例子中,同步和异步的判断条件就是老张得知水开了的方式,老张主动(站在水壶边/多次去查看)得到消息是就是同步,老张被动(水开了响水壶鸣笛提醒)得到消息就是异步。

用书面化一点的语言来说,就是

同步和异步关注的是消息通知机制

  1. 同步就是在发出一个调用时,没得到结果之前,该调用就不返回。但是一旦调用返回就得到返回值了,调用者主动等待这个调用的结果
  2. 异步就是在发出一个调用时,这个调用就直接返回了,不管返回有没有结果。当一个异步过程调用发出后,被调用者通过状态,通知来通知调用者,或者通过回调函数处理这个调用

(四)总结

所谓同步异步,只是对于水壶而言。普通水壶,同步;响水壶,异步。对应的就是消息通知机制。
虽然都能干活,但是响水壶可以在总结完工之后提醒老张水开了。同步只能让调用者去轮询自己(情况2中),造成老张效率低下。

所谓阻塞非阻塞,只是相对于老张而言,立等的老张,阻塞;看电视的老张,非阻塞。对应的就是程序等待结果时的状态。
情况1和情况3中老航就是阻塞的,我们也可以看到虽然情况3中水壶是异步的,但是并没有什么意义,因为老张还是浪费时间在旁边等着。所以一般异步是配合非阻塞使用的,这样才能发挥出异步的作用。

经过这样一番理解,我相信文章开头提出的几个问题也都豁然开朗了。