1.什么是BIO
BIO 就是传统的 java.io 包,它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是
说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调
用时可靠的线性顺序。它的有点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很
低,容易成为应用性能瓶颈。
2 什么是NIO
是 Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以构建
多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。
3 什么是AIO
AIO 是 Java 1.7 之后引入的包,是 NIO 的升级版本,提供了异步非堵塞的 IO 操作方式,所以
人们叫它 AIO(Asynchronous IO),异步 IO 是基于事件和回调机制实现的,也就是应用操
作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续
的操作
4 同步与异步
同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任
务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可
以保持一致。而异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工
作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是
否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。我们可以用打电话和发短
信来很好的比喻同步与异步操作。
5 阻塞与非阻塞
阻塞与非阻塞主要是从 CPU 的消耗上来说的,阻塞就是 CPU 停下来等待一个慢的操作完成
CPU 才接着完成其它的事。非阻塞就是在这个慢的操作在执行时 CPU 去干其它别的事,等这
个慢的操作完成时,CPU 再接着完成后续的操作。虽然表面上看非阻塞的方式可以明显的提高
CPU 的利用率,但是也带了另外一种后果就是系统的线程切换增加。增加的 CPU 使用时间能
不能补偿系统的切换成本需要好好评估。
6. 通道是个什么意思?
通道是对原 I/O 包中的流的模拟。到任何目的地(或来自任何地方)的所有数据都必须通过
一个 Channel 对象(通道)。一个 Buffer 实质上是一个容器对象。发送给一个通道的
所有对象都必须首先放到缓冲区中;同样地,从通道中读取的任何数据都要读到缓冲区
中。Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比
较,通道就像是流。
正如前面提到的,所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道
中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道
中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
7.缓冲区是什么意思?
Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。在 NIO 中加入 Buffer 对
象,体现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者
将数据直接读到 Stream 对象中
在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中
的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它
放到缓冲区中。
缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。
但是一个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟
踪系统的读/写进程
8.IO多路复用的底层原理
IO多路复用使用两个系统调用(select/poll/epoll和recvfrom),blocking IO只调用了
recvfrom;select/poll/epoll 核心是可以同时处理多个connection,而不是更快,所以连接
数不高的话,性能不一定比多线程+阻塞IO好,多路复用模型中,每一个socket,设置为non- blocking,阻塞是被select这个函数block,而不是被socket阻塞的。
1)select机制
客户端操作服务器时就会产生这三种文件描述符(简称fd):writefds(写)、readfds(读)、和
exceptfds(异常)。select会阻塞住监视3类文件描述符,等有数据、可读、可写、出异常 或超
时、就会返回;返回后通过遍历fdset整个数组来找到就绪的描述符fd,然后进行对应的IO操
作。
优点:
几乎在所有的平台上支持,跨平台支持性好
缺点:
由于是采用轮询方式全盘扫描,会随着文件描述符FD数量增多而性能下降。
每次调用 select(),需要把 fd 集合从用户态拷贝到内核态,并进行遍历(消息传递都是从
内核到用户空间)
默认单个进程打开的FD有限制是1024个,可修改宏定义,但是效率仍然慢。
2)poll机制
基本原理与select一致,只是没有最大文件描述符限制,因为采用的是链表存储fd。 3)epoll机制
epoll之所以高性能是得益于它的三个函数
1)epoll_create()系统启动时,在Linux内核里面申请一个B+树结构文件系统,返回
epoll对象,也是一个fd 2)epoll_ctl() 每新建一个连接,都通过该函数操作epoll对象,在这个对象里面修改添加
删除对应的链接fd, 绑定一个callback函数。
3)epoll_wait() 轮训所有的callback集合,并完成对应的IO操作
优点:
没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个
句柄
效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降
内核和用户空间mmap同一块内存实现
谈谈reactor模型?
4NIO同步非阻塞
NIO基于Reactor,当socket有流可读或可写入socket,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。也就是,不是一个链接就要对应一个处理线程,而是一个有效请求对应一个线程,当连接没有数据时,是没有工作线程来处理的
Reactor模型
nio只有acceptor的服务线程是堵塞进行的,其他读写线程是通过注册事件的方式,有读写事件激活时才调用线程资源区执行,不会一直堵塞等着读写操作,Reactor的瓶颈主要在于acceptor的执行,读写事件也是在这一块分发
5AIO异步非堵塞IO
AIO需要一个链接注册读写事件和回调方法,当进行读写操作时,只须直接调用API的read或write方法即可,这两种方法均为异步,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序
即,read/write方法都是异步的,完成后会主动调用回调函数
《Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!》:https://segmentfault.com/a/1190000021091737?utm_source=tag-newest