同步、异步、阻塞、非阻塞的区别和联系

首先,阻塞、非阻塞和同步、异步没有任何关系,好多人都认为同步就是阻塞,异步就是非阻塞,这一观点认为是不正确的!!

首先来解释同步和异步的概念,这两个概念与消息的通知机制有关.更多涉及多线程之间的交互:

案例分析:

比如我去银行办理业务,可能选择排队等候,也可能取一个小纸条上面有我的号码,等到排到我这一号时由柜台的人通知我轮到我去办理业务了.。

前者(排队等候)就是同步等待消息,而后者(等待别人通知)就是异步等待消息.在异步消息处理中,等待消息者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码)找到等待该事件的人.

同步:
    所谓的同步就是,就是在发出一个功能的调用时,在没有等到结果之前,该调用就不返回。并且在同一时间段只有一个线程运行,线程一定安全的!


异步(个人理解开辟一个新的线程去做某件事):
    当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。 一般异步调用等待消息者往往注册一个回调机制,在所等待机制触发时触发机制,通过某种机制找到等待该事件的人

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态

阻塞:
     阻塞调用是指调用结果返回之前,当前线程会被挂起(不可以做其他事情)。函数只有在得到结果之后才会返回。线程进入非可执行状态,在       这个状态下,cpu不会给线程分配时间片,即线程暂停运行
非阻塞:
     非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回,还可以做其他的事情

继续上面的那个例子,不论是排队还是使用号码等待通知,如果在这个等待的过程中,等待者除了等待消息之外不能做其它的事情,那么该机制就是阻塞的,表现在程序中,也就是该程序一直阻塞在该函数调用处不能继续往下执行.相反,有的人喜欢在银行办理这些业务的时候一边打打电话发发短信一边等待,这样的状态就是非阻塞的,因为他(等待者)没有阻塞在这个消息通知上,而是一边做自己的事情一边等待.但是需要注意了,第一种同步非阻塞形式实际上是效率低下的,想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,如果把打电话和观察排队的位置看成是程序的两个操作的话,这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的;而后者,异步非阻塞形式却没有这样的问题,因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不同的操作中来回切换. 。

很多时候同步操作会以阻塞的形式表现出来,也就是BIO,同步式非阻塞在JDK1.4出来的,还有就是异步非阻塞,这个在JDK1.8中有的。

扫描二维码关注公众号,回复: 10127961 查看本文章

通俗易懂案例二:

九哥爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1、 九哥把水壶放到火上,立等水开。(同步阻塞
九哥觉得自己有点傻
2 、九哥把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞
九哥还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3、 九哥把响水壶放到火上,立等水开。(异步阻塞
九哥觉得这样傻等意义不大
4、 九哥把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞
九哥觉得自己聪明了。

深入理解:
阻塞就是 recv/read的时候 socket接收缓冲区要是有数据就读, 没数据我就一直睡觉赖着不走,直到有数据来了读完我才走。send/write的时候,要是发送缓冲区满了,没有空间继续发送了我也一直睡觉赖着不走,直到发送缓冲区腾出足够的空间让我把数据全部塞到发送缓冲区里我才走。(当然如果你通过setsockopt设置了读写超时,超时时间到了还是会返回-1和EAGAIN,不再睡觉等待)
非阻塞就是recv/read的时候,要是接收缓冲区有数据我就读完,没有数据我直接带着返回的-1和EGAIN走人,绝不睡觉等待耽误时间。write/send的时候, 要是发送缓冲区有足够的空间,就立刻把数据塞到发送缓冲区去,然后走人,如果发送缓存区满了,空间不足,那直接带着返回的-1和EAGAIN走人。

至于IO多路复用,首先要理解的是,操作系统为你提供了一个功能,当你的某个socket接收缓存区有数据可读,或者发送缓冲区有空间可写的时候,它可以给你一个通知。这样当配合非阻塞的socket使用时,只有当系统通知我哪个描述符可读了,我才去执行read操作,可以保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功。写操作类似。操作系统的这个功能通过select/poll/epoll之类的系统调用函数来使用,这些函数都可以同时监视多个描述符的读写就绪状况,这样,多个描述符的I/O操作都能在一个线程内完成,这就叫I/O多路复用,这里的“复用”指的是复用同一个线程。这就是同步非阻塞,Netty框架也是同步非阻塞的。

至于事件驱动,其实是I/O多路复用的一个另外的称呼。

I/O多路复用参考:https://blog.csdn.net/u011109589/article/details/80333775

发布了23 篇原创文章 · 获赞 12 · 访问量 9535

猜你喜欢

转载自blog.csdn.net/geng2568/article/details/103170164