Java中IO框架
1、知识体系
2、NIO(New IO)
NIO(New IO),它是一种同步非阻塞I/O模型,也是 I/O多路复用的基础,在高并发,大量连接等场景有着比较明显的优势。
NIO是一种基于通道和缓冲区的I/O方式,主要有三大核心组件:Channel(通道),Buffer(缓冲区), Selector(选择器)。当线程对数据进行操作时,先从Channel将数据读取到Buffer,或者从缓冲区将数据写入到Channel。Selector用于监听多个通道的事件,来通知连接打开,数据到达等操作,一个线程可以监听多个数据通道。
2.1、缓存区(Buffer)
通常情况下,操作系统的一次写操作分为两步 : 1. 将数据从用户空间拷贝到系统空间。 2. 从系统空间往网卡写。同理,读操作也分为两步: ① 将数据从网卡拷贝到系统空间; ② 将数据从系统空间拷贝到用户空间。
对于NIO来说,缓存的使用可以使用 DirectByteBuffer(堆外)和HeapByteBuffer(堆内) (DirectByteBuffer底层实现是数组)。如果使用了DirectByteBuffer,一般来说可以减少一次系统空间到用户空间的拷贝。但Buffer创建和销毁的成本更高,更不宜维护,通常会用内存池来提高性能。
2.2、通道(Channel)
通道(Channel):由java.nio.channels包定义的。Channel表示IO源与目标打开的连接。Channel类似于传统的“流”。只不过Channel本身不能直接访问数据,Channel只能与Buffer进行交互。
Channel和传统IO中的Stream很相似。主要区别在于:通道它是双向的,它既可以进行读,也可以进行写。但Stream只能进行单向操作,例如InputStream只能进行读取操作,OutputStream只能进行写操作。
2.3、选择器(Selector)
选择器(Selector)是SeIectabIeChannIe对象的多路复用器,Selector可以同时监控多个SelectableChannel 的IO状况,也就是说,利用Selector可使一个单独的线程管理多个Channel,其中在Win系统里面Selector默认的是Select函数,Linux默认的是epoll函数。
Selector是非阻塞IO的核心
//1.获取通道
ServerSocketChannel ssChannel = ServerSocketChannel.open();
//2.切换非阻塞模式
ssChannel.configureBlocking(false);
//3.绑定连接
ssChannel.bind(new InetSocketAddress(9898));
//4.获取选择器
Selector selector = Selector.open();
//5.将通道注册到选择器上,并且指定“监听接收事件”
ssChannel.register(select,SelectionKey.OP_ACCEPT);
2.4、Select函数和EPOLL函数、POLL函数
(1)Select函数
(2)EPOLL函数
(3)POLL函数
5、Linux五种IO模型
5.1、阻塞式IO(BIO)
应用进程 通过recvfrom()从socket接受数据报被阻塞,直到数据复制到应用进程缓冲区中才返回。
注意:recvfrom从socket接收数据,select是从文件系统读取数据。
5.2、非阻塞式IO(NIO)
应用进程 执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是 需要不断的 执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。
5.3、IO多路复用
上面介绍的I/O模型都是应用程序直接发起I/O操作,而I/O Multiplexing首先应用程序先向kernel发起system call(select()),传入file descriptor和事件(readable、writable等)让kernel监测,当其中一个或多个fd数据就绪,就会返回结果,程序再发起真正的I/O操作(resvfrom());
5.4、信号驱动IO
这种信号驱动的I/O并不常见,从图片可以看到它第一次发起system call不会阻塞进程,kernel的数据就绪后会发送一个signal给进程。进程发起真正的IO操作。
5.5、异步IO(AIO)
异步I/O,即I/O操作不会引起进程阻塞。请看上图,发起aio_read请求后,kernel会直接返回。等数据就绪,发送一个signal到process处理数据。
注意:程序不需要再次发起读取数据的system call,因为kernel会把数据复制到user space再通知进程处理,整个过程不存在任何阻塞。
特别注意: select、poll、epoll并不是I/O操作,read、recvfrom这些才是。