NIO、BIO、AIO的区别
1. ⾯试题分析
IO模型分类
BIO、NIO、AIO IO与NIO区别
同步与异步的区别
阻塞和⾮阻塞
分析需要全⾯并且有深度
容易被忽略的坑
分析⽚⾯
没有深⼊
2. IO模型主要分类
同步(synchronous) IO和异步(asynchronous) IO
阻塞(blocking) IO和⾮阻塞(non-blocking)IO
同步阻塞(blocking-IO)简称BIO
同步⾮阻塞(non-blocking-IO)简称NIO
异步⾮阻塞(synchronous-non-blocking-IO)简称AIO
BIO (同步阻塞I/O模式) 数据的读取写⼊必须阻塞在⼀个线程内等待其完成。 这⾥使⽤那个经典的烧开⽔例⼦,这⾥假设⼀个烧开⽔的场景,有⼀排⽔壶在烧开 ⽔,BIO的⼯作模式 就是, 叫⼀个线程停留在⼀个⽔壶那,直到这个⽔壶烧开,才去处理下⼀个⽔壶。但是实际上线程在等 待⽔壶烧开的时间段什么都没有做。
NIO(同步⾮阻塞) 同时⽀持阻塞与⾮阻塞模式,但这⾥我们以其同步⾮阻塞I/O模式来说明,那么什么叫做同步⾮阻塞?如 果还拿烧开⽔来说,NIO的做法是叫⼀个线程不断的轮询每个⽔壶的状态,看看是否有⽔壶的状态发⽣ 了改变,从⽽进⾏下⼀步的操作。
AIO (异步⾮阻塞I/O模型)
异步⾮阻塞与同步⾮阻塞的区别在哪⾥?异步⾮阻塞⽆需⼀个线程去轮询所有IO操作的状态改变,在相 应的状态改变后,系统会通知对应的线程来处理。对应到烧开⽔中就是,为每个⽔壶上⾯装了⼀个开 关,⽔烧开之后,⽔壶会⾃动通知我⽔烧开了。
IO与NIO区别
同步与异步的区别
同步:发送⼀个请求,等待返回,再发送下⼀个请求,同步可以避免出现死锁,脏读的发⽣。
异步:发送⼀个请求,不等待返回,随时可以再发送下⼀个请求,可以提⾼效率,保证并发。
阻塞和⾮阻塞
阻塞:传统的IO流都是阻塞式的。也就是说,当⼀个线程调⽤read()或者write()⽅法时,该线程将被阻 塞,直到有⼀些数据读读取或者被写⼊,在此期间,该线程不能执⾏其他任何任务。在完成⽹络通信进 ⾏IO操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供⼀个独⽴的线程进⾏处理,当服 务器端需要处理⼤量的客户端时,性能急剧下降。
⾮阻塞:Java NIO是⾮阻塞式的。当线程从某通道进⾏读写数据时,若没有数据可⽤时,该线程会去执⾏其他任务。 线程通常将⾮阻塞IO的空闲时间⽤于在其他通道上执⾏IO操作,所以单独的线程可以管理多个输⼊和输 出通道。因此NIO可以让服务器端使⽤⼀个或有限⼏个线程来同时处理连接到服务器端的所有客户端。
BIO、NIO、AIO适⽤场景
BIO⽅式适⽤于连接数⽬⽐较⼩且固定的架构,这种⽅式对服务器资源要求⽐较⾼,并发局限于应 ⽤中,JDK1.4以前的唯⼀选择。
NIO⽅式适⽤于连接数⽬多且连接⽐较短(轻操作)的架构,⽐如聊天服务器,并发局限于应⽤ 中,编程⽐较复杂。
AIO⽅式使⽤于连接数⽬多且连接⽐较⻓(重操作)的架构,⽐如相册服务器,充分调⽤OS参与并 发操作,编程⽐较复杂,JDK7开始⽀持。
3. NIO的3个核⼼概念
NIO重点是把Channel(通道),Buffer(缓冲区),Selector(选择器)三个类之间的关系弄清楚。
缓冲区Buffer Buffer是⼀个对象。它包含⼀些要写⼊或者读出的数据。在⾯向流的I/O中,可以将数据写⼊或者将数据 直接读到Stream对象中。
在NIO中,所有的数据都是⽤缓冲区处理。这也就本⽂上⾯谈到的IO是⾯向流的,NIO是⾯向缓冲区 的。 缓冲区实质是⼀个数组,通常它是⼀个字节数组(ByteBuffer),也可以使⽤其他类的数组。但是⼀个 缓冲区不仅仅是⼀个数组,缓冲区提供了对数据的结构化访问以及维护读写位置(limit)等信息。
最常⽤的缓冲区是ByteBuffer,⼀个ByteBuffer提供了⼀组功能于操作byte数组。除了ByteBuffer,还 有其他的⼀些缓冲区,事实上,每⼀种Java基本类型(除了Boolean)都对应⼀种缓冲区,具体如下:
ByteBuffer:字节缓冲区
CharBuffer:字符缓冲区
ShortBuffer:短整型缓冲区
IntBuffer:整型缓冲区
LongBuffer:⻓整型缓冲区
FloatBuffer:浮点型缓冲区
DoubleBuffer:双精度浮点型缓冲区
通道Channel
Channel是⼀个通道,可以通过它读取和写⼊数据,他就像⾃来⽔管⼀样,⽹络数据通过Channel读取和 写⼊。
通道和流不同之处在于通道是双向的,流只是在⼀个⽅向移动,⽽且通道可以⽤于读,写或者同时⽤于 读写。
因为Channel是全双⼯的,所以它⽐流更好地映射底层操作系统的API,特别是在UNIX⽹络编程中,底 层操作系统的通道都是全双⼯的,同时⽀持读和写。
Channel有四种实现:
FileChannel:是从⽂件中读取数据。
DatagramChannel:从UDP⽹络中读取或者写⼊数据。
SocketChannel:从TCP⽹络中读取或者写⼊数据。
ServerSocketChannel:允许你监听来⾃TCP的连接,就像服务器⼀样。每⼀个连接都会有⼀个 SocketChannel产⽣。
多路复⽤器Selector
Selector选择器可以监听多个Channel通道感兴趣的事情(read、write、accept(服务端接收)、 connect,实现⼀个线程管理多个Channel,节省线程切换上下⽂的资源消耗。Selector只能管理⾮阻塞 的通道,FileChannel是阻塞的,⽆法管理。
关键对象
Selector:选择器对象,通道注册、通道监听对象和Selector相关。
SelectorKey:通道监听关键字,通过它来监听通道状态。
监听注册
监听注册在Selector
socketChannel.register(selector, SelectionKey.OP_READ);
监听的事件有
OP_ACCEPT: 接收就绪,serviceSocketChannel使⽤的
OP_READ: 读取就绪,socketChannel使⽤
OP_WRITE: 写⼊就绪,socketChannel使⽤
OP_CONNECT: 连接就绪,socketChannel使⽤
扩展内容 NIO、BIO、AIO的应⽤和框架选型
作者:奇点在掘金
链接:https://juejin.cn/post/7022145536639631397