从同步阻塞聊到Java三种IO方式

本文总结自
 
 
快速理解
首先,我们要先对这几个概念有一个直观的理解,对于初学者来说,你可以这样看待这几个概念:
  • 阻塞非阻塞 指的是在客户端
    • 阻塞:意味着 客户端提出一个请求以后,在得到回应之前,只能等待
    • 非阻塞:意味着 客户端提出一个请求以后,在得到回应之前,客户端还可以做其他事情
  • 同步异步 指的是服务器端
    • 同步:意味着 服务器接受一个请求后,在返回结果以前不能做其他的事情
    • 异步:意味着 服务器接受一个请求后,尽管还没有返回结果,但是可以做其他的事情
这样的理解其实是过于以偏概全的,因为这只是消息通知场景中的解释,但是通过代入客户端,服务器端更加方便初学者理解,因此在这里,暂且先这样解释。
 
 
举个例子
小明领着女朋友去超市购物,买了很多东西,当他走到收银员那里结账的时候,小明(客户端)发出了要求结账的讯息(请求),收银员(服务器)会对他这一要求进行处理。此时有可能产生多种场景
  • 小明傻傻地等着收银员用计算器算出所有物品的总价,并准备付款。(同步阻塞小明在请求响应之前,一直在等待;收银员没有做别的事情,一直在处理小明的请求)
  • 小明觉得自己太傻了,于是一边和女朋友聊天,一边催促收银员快点计算出总价。(同步非阻塞小明在请求响应之前,做了其他的事情;收银员一直在处理小明的请求)
  • 小明傻傻地等着收银员的总价结果,收银员却把计算的工作交给计算机之后就去拿袋子帮忙装东西,直到计算机上出现了总价结果,收银员才继续回来完成收款工作。(异步阻塞小明在请求响应之前,一直在等待;收银员在处理小明请求的过程中,处理了其他的事情)
  • 小明觉得自己太傻了,于是一边和女朋友聊天,一边催出收银员快点计算出总价,而收银员却把计算的工作交给计算机之后就去拿袋子帮忙装东西,直到计算机上出现了总价结果,收银员才继续回来完成收款工作。(异步非阻塞小明在请求响应之前做了其他的事情;收银员也在处理请求的过程中,处理了其他的事情)
在这个例子中:
  • 阻塞,非阻塞,指的是小明是否在等待处理结果的过程中去做了其他的事情。
  • 同步,异步,指的是收银员是否在处理收款这一请求的过程中去做了其他的事情,这也导致了收款的结果是当时告诉了小明,还是之后又进行了额外的通知。
 
再来个例子
老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
  1. 老张把水壶放到火上,立等水开。(同步阻塞)老张觉得自己有点傻
  2. 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的响声。
  3. 老张把响水壶放到火上,立等水开。(异步阻塞)老张觉得这样傻等意义不大
  4. 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞
在这个例子中:
  • 所谓同步异步,只是对于水壶而言。
    • 普通水壶,同步;响水壶,异步。
    • 虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
    • 同步只能让调用者老张去轮询自己(情况2中),造成老张效率的低下。
  • 所谓阻塞非阻塞,仅仅对于老张而言。
    • 立等的老张,阻塞;看电视的老张,非阻塞。
    • 情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。
一般异步是配合非阻塞使用的,这样才能发挥异步的效用
 
 
结论:
阻塞和非阻塞:关注的是调用者是否会一直等待被调用者的通知。换句话说,发出请求者是否会在等待过程中去做别的事情。
同步和异步:关注的是被调用者是否会一直处理该请求。换句话说,处理请求者是持续处理该请求并通过原调用将结果返回,还是可以在该请求处理完成前处理其他事情,并在该请求完成时通过其他方式将结果通知调用者。
 
 
深入探究
一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作。
阻塞IO和非阻塞IO的区别在于发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。
同步IO和异步IO的区别就在于实际的IO操作是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO。
 
阻塞和非阻塞是针对于进程在访问数据的时候,根据IO请求的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值。
同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询(轮询的时候不干别的事情)的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。
 
所以,IO操作可以分为3类:同步阻塞(即早期的IO操作,BIO)、同步非阻塞NIO)、异步非阻塞AIO)。
  • 同步阻塞:在此种方式下,用户进程在发起一个IO请求以后,必须等待IO请求的返回,只有当IO请求返回以后,用户进程才能继续运行。JAVA传统的IO模型(BIO)属于此种方式。
  • 同步非阻塞:在此种方式下,用户进程发起一个IO请求以后便可以返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。
  • 异步非阻塞:此种方式用户进程发起一个IO请求后,便返回做其他事情,而真正处理IO的应用发起一个IO操作以后,不等待内核IO操作的完成,也可以处理其他事情,等内核完成IO操作以后会通知处理IO的应用,处理IO的应用再通知用户进程。目前JAVA中的AIO就属于异步非阻塞IO。
 
 
Java三种IO的历史
BIO:JDK1.4之前
NIO:JDK1.4推出了java.nio包
AIO:JDK1.7在java.nio.channels包下新增了四个异步通道
  1. AsynchronousSocketChannel
  2. AsynchronousServerSocketChannel
  3. AsynchronousFileChannel
  4. AsynchronousDatagramChannel
posted @ 2018-03-25 23:11  noodleprince  阅读(204)  评论(0编辑  收藏  举报