我们正常传统的通过流读取文件是阻塞式的 效率比较低,今天就来了解下java io的几种方式
对比
对比总结 | BIO | NIO | AIO |
---|---|---|---|
IO方式 | 同步阻塞 | 同步非阻塞 | 异步非阻塞 |
API使用难度 | 简单 | 复杂 | 复杂 |
可靠性 | 低 | 高 | 高 |
吞吐量 | 低 | 高 | 高 |
BIO
适用于连接较少,对服务器资源消耗很大,但是编程简单。是同步阻塞的。
举例:你到餐馆点餐,然后在那儿等着,什么也做不了,只要饭还没有好,就要必须等着
NIO
使用于连接数量比较多且连接时间比较短的架构,比如聊天服务器,编程比较复杂。是同步非阻塞的
举例:你到餐馆点完餐,然后就可以去玩儿了,玩一会儿就回饭馆问一声,饭好了没。
AIO
适用于连接数量多而且连接时间长的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂。是异步非阻塞的。
举例:饭馆打电话给你说,我们知道你的位置,待会儿给您送来,你安心的玩儿就可以了。类似于外卖。
一、传统IO(BIO)
和一般的请求一样一个io请求需要一个线程处理,而且线程处理的时候是阻塞的,必须等待响应
二、NIO(同步非阻塞IO/多路复用IO)
NIO是对BIO的改进,它是同步非阻塞的IO,以块的方式处理数据(效率高)。NIO基于通道和缓冲区进行数据操作,数据总是从通道读取到缓冲区中,或者从缓冲区中写到通道中。Selector(选择器)用于监听多个通道的时间,(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道。其中NIO适合大文件的读写,小文件读写效率返回更低(因为这时候创建channel时间不可忽略)
NIO 主要是由 Channel(通道)、Buffer(缓冲区)、Selector(选择器)组成,
主要步骤和元素:
-
首先,通过 Selector.open() 创建一个 Selector,作为类似调度员的角色。
-
然后,创建一个 ServerSocketChannel,并且向 Selector 注册,通过指定 SelectionKey.OP_ACCEPT,告诉调度员,它关注的是新的连接请求。
-
注意,为什么我们要明确配置非阻塞模式呢?这是因为阻塞模式下,注册操作是不允许的,会抛出 IllegalBlockingModeException 异常。
-
Selector 阻塞在 select 操作,当有 Channel 发生接入请求,就会被唤醒。
-
在 具体的 方法中,通过 SocketChannel 和 Buffer 进行数据操作
IO 都是同步阻塞模式,所以需要多线程以实现多任务处理。而 NIO 则是利用了单线程轮询事件的机制,通过高效地定位就绪的 Channel,来决定做什么,仅仅 select 阶段是阻塞的,可以有效避免大量客户端连接时,频繁线程切换带来的问题,应用的扩展能力有了非常大的提高
三.AIO
AIO是异步IO的缩写,虽然NIO在网络操作中,提供了非阻塞的方法,但是NIO的IO行为还是同步的。对于NIO来说,我们的业务线程是在IO操作准备好时,得到通知,接着就由这个线程自行进行IO操作,IO操作本身是同步的。
但是对AIO来说,则更加进了一步,它不是在IO准备好时再通知线程,而是在IO操作已经完成后,再给线程发出通知。因此AIO是不会阻塞的,此时我们的业务逻辑将变成一个回调函数,等待IO操作完成后,由系统自动触发。
与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。