我们来聊聊Java BIO、NIO、AIO的原理和区别,以及同步、异步、阻塞、非阻塞和多路复用这些概念。
同步与异步:等待的艺术
想象一下,你是一位餐厅的顾客,而你的餐点(数据)正在厨房里准备。
同步:就像是你坐在桌子旁,耐心等待你的餐点完全准备好,厨师才会把它端给你。在这期间,你不能做其他事情,只能干等。
异步:这就像是你点了餐,然后告诉服务员你稍后会回来取。这样你就可以去做其他事情,比如刷手机或和朋友聊天,直到服务员(内核)告诉你餐点已经准备好了。
也即是同步和异步是针对用户进程如何获取结果来说的,同步是指用户进程需要等待数据全部准备完成并返回结果了,才能进行其他任务;而异步则是先发个消息给内核,然后直接去执行其他任务不进行等待,最后等待内核执行反向通知用户进程。
阻塞与非阻塞:忙碌与悠闲
继续餐厅的比喻,想象一下你在等待服务员上菜。
阻塞:你坐在桌子旁,服务员告诉你菜还在准备中,你必须坐在那里等,直到菜端上来。
非阻塞:服务员告诉你菜还没好,你可以先去忙别的,等菜好了再回来。这样你就可以去吧台喝一杯,或者去洗手间,不用一直坐在桌子旁。
通过上篇文章 零拷贝的原理是什么?,我们已经知道了IO的交互分为2个步骤:第一步是等待数据,第二步是从内核拷贝到用户空间。
阻塞和非阻塞针对的就是在这2个步骤中,用户进程是直接挂起等到2个步骤都完成,还是不断询问内核是否完成第一步,然后再完成第二步,这个过程可以执行其他任务,不会阻塞等待。
多路复用:服务员的超能力
多路复用:这就像是服务员拥有超能力,可以同时关注多张桌子,一旦某张桌子上的菜准备好了,他就会立刻过去服务,而不需要每张桌子都一直盯着。
BIO、NIO、AIO:餐厅服务模式
BIO:这就像是一家老式餐厅,每张桌子都有一个服务员,当顾客(请求)到来时,服务员必须全程陪伴,直到顾客用餐完毕。这种方式适合顾客不多的情况,但如果顾客太多,服务员就会忙不过来。
因此BIO的特点就是应用程序全程阻塞等待,不适合高并发应用,每个请求都需要使用一个线程处理,资源消耗大,仅适合并发量低的应用,过程如下:
NIO:这就像是一家现代化的自助餐厅,服务员(Selector)不需要一直陪着顾客,而是在顾客需要服务时才过去。这种方式适合高并发的情况,因为服务员可以同时照顾多张桌子。
因此NIO的特点就是基于多路复用,可以同时处理多个连接的请求响应,采用Reactor线程模式,适合高并发应用,过程如下:
AIO:这就像是一家高科技的未来餐厅,顾客点了餐之后就可以去做其他事情,等到餐点准备好了,餐厅会自动通过某种方式通知顾客。这种方式最适合高并发,因为顾客和服务员都不需要一直等待。
因此AIO的特点就是应用程序不会阻塞等待,数据一步到位,才有Proactor模式,适合高并发应用,过程如下:
面向流与面向缓冲区:不同的用餐方式
BIO:就像是你只能吃流水席,一旦坐下来,就必须一直吃到结束,中间不能停下来。
因此BIO是面向流的,每次从流中读取的数据没有地方缓存,直到读完为止,因此无法前后移动偏移量从流中读取指定的数据。
NIO:这就像是你可以先点一桌菜,然后想吃哪个就吃哪个,还可以根据需要调整顺序。
因此NIO是面向缓冲区的,先将数据读取到缓冲区,然后可以根据需要前后移动偏移量读取数据,比较灵活。
通过这些幽默的比喻,我们可以更轻松地理解Java BIO、NIO、AIO的原理和区别,以及同步、异步、阻塞、非阻塞和多路复用这些概念。