Java中的IO模型
Java中的IO模型有三种:
- 同步阻塞IO(BIO, JDK1.4之前就支持)
- IO多路复用(NIO, JDK1.4版本支持,java.nio包)
- 异步IO(AIO, JDK1.7中支持)
其中IO多路复用,也属于同步IO。另外在Unix系统中,除了上面3中IO模型之外还有“信号驱动IO”,它也属于同步IO。
阻塞IO 和 非阻塞IO 这两个概念是程序级别的。主要描述的是程序请求操作系统IO操作后,如果IO资源没有准备好,那么程序该如何处理的问题:前者等待;后者继续执行(并且使用线程一直轮询,直到有IO资源准备好了)
2020-08-22补充:数据就绪前要不要等待。阻塞是指没有数据传过来时,读操作会一直阻塞知道有数据,缓冲区满时,写操作也会阻塞;而非阻塞遇到这种情况都是直接返回。
同步IO 和 非同步IO这两个概念是操作系统级别的。主要描述的是操作系统在收到程序请求IO操作后,如果IO资源没有准备好,该如何相应程序的问题:前者不响应,直到IO资源准备好以后;后者返回一个标记(好让程序和自己知道以后的数据往哪里通知),当IO资源准备好以后,再用事件机制返回给程序。
2020-08-22补充:同步异步指的是数据就绪后,数据操作谁来完成。如果数据就绪后需要自己去读就是同步;如果是数据就绪了直接读好再回调给程序则是异步。
网上流传的例子
老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1 老张把水壶放到火上,立等水开。(同步阻塞)老张觉得自己有点傻
2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3 老张把响水壶放到火上,立等水开。(异步阻塞)老张觉得这样傻等意义不大
4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)老张觉得自己聪明了。
所谓同步异步,只是对于水壶而言。普通水壶,同步;响水壶,异步。虽然都能干活,但响水壶可以在自己完工之后,提示老张水开。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。所谓阻塞非阻塞,仅仅对于老张而言。立等的老张,
阻塞;看电视的老张,非阻塞。情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。
虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。
模型图
一般情况下,IO处理过程可以分为三步:
- 等待数据就绪(读就绪、写就绪);
- 将数据从内核中拷贝到JVM进程中;
- 处理数据。
非阻塞模式会不断发起系统调用询问数据准备好了没有,这会空耗CPU,故实际很少使用。I/O多路复用是对这个情况的改良,使用单独一个线程去轮询数据是否准备好了,而其他线程处理数据的读写(没有数据可以处理,就去做其他事)。
I/O多路复用的实现机制
- select
- poll
- epoll
select模型是由一个数组管理的,也就是每当注册一个感兴趣的事件时,就会占用一个数组的位置。由于是使用数组来存储事件的注册,所以就有长度限制,在32位机器上限制为1024,在64位机器上限制为2048。
每次系统请求时都会线性遍历整个数组看是否有可处理的事件,若没有则睡眠,直到超时或被事件触发唤醒后重新遍历,性能自然不怎么样。
poll和select很类似,最大的区别在于它不是用数组实现的,而是使用链表实现,因此它就没有select最大数量的限制了。
epoll基于事件回调机制,即回调时直接通知进程,而无须使用某种方式来查看状态。它通过mmap映射内存来实现,不用像select和poll一样需要内存拷贝。
参考链接:
http://blog.csdn.net/tanga842428/article/details/52793804
http://blog.csdn.net/column/details/sys-communication.html?&page=1
《Java特种兵上册》