NIO-阻塞和非阻塞(210114)

对于阻塞和非阻塞,同步和异步,再加上两者的组合实际上不太容易理解的概念,今天重新思考了下再做下整理和总结,供大家参考。为了更好的理解,我们还是拿张三请求李四帮他泡一壶茶来举例说明。这里面有两个角色,一个是请求者张三,一个是执行者李四。

同步和异步

对于同步和异步我在前面谈SOA和接口服务,消息中间件的时候经常会谈到。简单来讲同步就是连接一直保持着,等待对方返回结果。而异步则是先发出请求后直接返回,连接也关闭,同时同步另外一个接口来返回结果。

  • 同步:张三发出请求给李四,然后李四马上去执行泡茶,这里关键就是请求动作和执行动作是连在一起的,没有分离。
  • 异步:张三发出请求,李四告诉张三请求收到,张三即得到了返回。
    这个时候李四可能在做另外的事情,那么张三请求是进入了队列等待执行。即请求和执行本质是分离的。

阻塞和非阻塞

对于阻塞和非阻塞实际是针对请求者来说的,则在发送请求后是否需要一直处于等待状态,如果是的话则是阻塞,否的话则是非阻塞。

  • 阻塞:张三发起请求给李四,李四马上去执行泡茶,然后张三不能做其它事情一直在那等待。这个时候即是阻塞。
  • 非阻塞:张三发起请求给李四,张三就去忙其它事情,每5分钟都来问下李四茶泡好了没有。这个是非阻塞。重点是张三发出请求后能够去干其它事情。

两者组合场景说明

对于两者的组合实际上存在四种类型,即同步阻塞,同步非阻塞,异步阻塞,异步非阻塞。

  • 同步阻塞:张三发出请求给李四,李四马上执行泡茶,张三一直在等待不能做其它事情,直到拿到李四泡好的茶。
  • 同步非阻塞:张三发出请求给李四,李四马上执行泡茶,张三去溜达或干其它事,然后轮询茶泡好没有,直到拿到自己的茶。
  • 异步阻塞和异步非阻塞:张三发出请求,李四马上回应收到。因为张三已经收到请求收到的回应,这个请求线程已经结束了。由于请求线程很短,这个时候本身阻塞或非阻塞意义不大。

也就是说异步下谈阻塞或非阻塞没有意义。异步下本身请求线程马上就得到了返回,请求过程就已经结束,不存在请求线程还要挂起的情况。异步下不存在
非阻塞的必要性。同步下请求和执行线程是绑定的,异步下请求和执行线程是解耦开的,真正的执行线程完全新启的独立线程。

异步+轮询:
张三发出请求,李四回应收到,但是李四并没有马上去执行泡茶,而是放到自己的待办队列里面。当前面事情处理后后,李四才去泡茶。张三发起一个新线程,询问李四茶泡好没有,李四检查发现茶泡好了直接交付茶给张三。

异步+消息通知:
张三发出请求,李四回应收到,但是李四并没有马上去执行泡茶,而是放到自己的待办队列里面。当前面事情处理后后,李四才去泡茶,茶泡好,李四主动发消息通知李四查泡好了。张三这个时候仍然是新起到一个线程去茶拿回来。

对于同步非阻塞实际上当前使用很多的一个场景,简单来说对于请求端来说整体的感受仍然是同步请求,但是内部请求线程却没有被阻塞一直处于等待状态,这样就完全加大了中间件进行大并发访问和调用的处理性能和能力。这也是当前很多中间件采用NIO线程的一个关键原因。

对于接口服务调用哪种场景适合NIO?

对于传统的ESB服务总线或API网关在注册和接入接口服务的时候,可以看到存在一种接口服务调用,该类接口提供方在收到请求后需要经过后台长耗时的计算或查询处理才能够返回数据。在这种情况在实际请求端的连接处于一直保持状态。
如果存在大并发的类似接口服务调用,往往很快消耗完整个线程池可用线程。因此在这种情况下实际上适合采用同步NIO非阻塞模式来进行处理。