当前位置 : 主页 > 编程语言 > 其它开发 >

阻塞非阻塞和同步异步的区分 参考一些书籍

来源:互联网 收集:自由互联 发布时间:2022-07-04
编程中一直对这两个概念不是很理解,在网上搜了很多资料大概描述的其实都很模糊,有时候还自相矛盾,很容易搞混,这里说一下我对这两个概念的理解。 首先看一下相关技术书籍对

编程中一直对这两个概念不是很理解,在网上搜了很多资料大概描述的其实都很模糊,有时候还自相矛盾,很容易搞混,这里说一下我对这两个概念的理解。
首先看一下相关技术书籍对这两个概念的描述,下面分别是摘自《深入理解Java核心技术》和《Java并发程序设计中的》的内容。
摘自《深入理解Java核心技术》14.2:

当I/O操作发生时,一定是有两方参与的,分别是调用方和被调用方。阻塞和非阻塞描述的是调用方,同步和异步描述的是被调用方。
例如A调用B:
1.如果是阻塞,那么A在发出调用命令后,要一直等待B返回结果。
2.如果是非阻塞,那么A在发出调用命令后,不需要等待,可以去做自己的事情。
3.如果是同步,那么B在收到A的调用命令后,会立即执行要做的事,A的本次调用可以得到结果
4.如果是异步,那么B在收到A的调用命令后,不保证会立即执行要做的事,但是保证会做,B在做好了之后会通知A。A的本次调用得不到·结果,但是B执行完成要做的事之后会通知A。
因为同步/异步与阻塞/非阻塞描述的对象不同,所以这二者之间是没有必然联系的。也就是说,同步不一定阻塞,异步也不一定非阻塞。
只不过通常很少存在异步且阻塞的场景,所以很多人误以为同步一定是非阻塞的、异步一点事非阻塞的。

摘自《Java高并发程序设计》1.2:

同步和异步通常用来形容一次方法的调用。同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而异步方法通常会在另外一个线程中“真实”地执行。整个过程,不会阻碍调用者的工作。对于调用者来说,异步调用似乎是一瞬间就完成的。如果异步调用需要返回结果,那么当这个异步调用真实完成时,则会通知调用者。
阻塞和非阻塞通常用来形容多线程间的相互影响。比如一个线程占用了临界区资源,那么其他所有需要这个资源的线程就必须在这个临界区中进行等待。等待会导致线程挂起,这种情况就是阻塞。此时,如果占用资源的线程一直不愿意释放资源,那么其他所有阻塞在这个临界区上的线程都不能工作。 非阻塞的意思与之相反,它强调没有一个线程可以妨碍其他线程执行。所有的线程都会尝试不断前向执行。

两本书籍的描述切入点不一样,乍一看两个书籍描述的可能还有点冲突,反而让人更迷糊。
在我看来阻塞和非阻塞必然是线程或进程相关的,阻塞指的是如果线程无法立即完成任务是否会进入阻塞状态,非阻塞则与之相反。
同步即所有的代码都是按顺序执行的,可以理解为这个事情不干完了我就不干别的事情。异步则不可预测顺序的,异步调用必须伴随着通知,可以理解为等到取值完成后我再进行后续的操作,我先去干别的事情。

同步异步和阻塞非阻塞搭配就会出现如下四种组合:

  1. 同步阻塞,如果不能立即获取数据,则线程阻塞等待数据返回。因为程序阻塞了,需要有其他程序将程序唤醒(这里很重要),如java类FileInputStream的readBytes操作。
  2. 同步非阻塞,如果不能立即获取数据,则循环检查数据是否完成。这里不需要其他线程参与唤醒操作。比如java类AtomicInteger的自增操作,如果不能加1就循环执行。
  3. 异步非阻塞,如果不能立即获取数据,则立即返回执行其他操作。等到数据返回了,接收到通知后再进行后续的处理工作(这里后续的处理操作是别的线程去做了,因为当前线程可能已经退出了)。
  4. 异步阻塞,这应该是一个并不存在的组合,异步和阻塞是互斥的。既然都可以异步执行,你还阻塞干什么呢,执行完成之后再通知你不就好了吗,异步的目的不就是无法立即获取数据让线程去干别的事情吗,如果没有别的事情可做就同步阻塞等待就可以了

总结:
如果一个程序说他是异步的,那他肯定非阻塞的,因为并不存在异步阻塞。开启异步的目的就是不想让当前线程阻塞,让他去干其他事情。就是你需要获取一个资源或发出一个通知,但是你并不能立即获取这个资源或者知道通知是否发送成功,这个时候你就需要线程去干别的事(这里的别的事指不依赖前面调用返回结果的代码)。等结果出来了再对结果进行处理,如对资源解析或者重新发送消息。

网友评论