文章目录
出自 github
定义:Java中BIO、NIO、AIO是Java语言对于操作系统的各种IO模型的封装。
常见概念:
同步与异步:
- 同步:是发起一个调用后,被调用者未处理完请求之前,调用不会返回。
- 异步:是发起一个调用之后,立刻得到被调用者回应表示已经接收到请求。但返回的并不是结果,这是调用者可以去处理其他的请求,被调用者通常依靠事件、回调等机制来通知调用者其返回结果。
- 区别:同步需要调用者等待结果,而异步不需要调用者等待结果,被调用者会通过回调等机制来通知调用者其返回结果。
阻塞和非阻塞:
- 阻塞:发起一个请求,调用者会一直等待请求结果的返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
- 非阻塞:发起一个请求,不用一直等待返回结果,可以先去处理其他事情。
- 生活例子:
举个生活中简单的例子,你妈妈让你烧水,小时候你比较笨啊,在那里傻等着水开(同步阻塞)。等你稍微再长大一点,你知道每次烧水的空隙可以去干点其他事,然后只需要时不时来看看水开了没有(同步非阻塞)。后来,你们家用上了水开了会发出声音的壶,这样你就只需要听到响声后就知道水开了,在这期间你可以随便干自己的事情,你需要去倒水了(异步非阻塞)。
BIO(Blocking I/O)
同步阻塞I/O模式,数据读取写入必须阻塞在一个线程内等待其完成。
传统BIO(一请求一应答通信模型)
采用 BIO 通信模型 的服务端,通常由一个独立的 Acceptor 线程负责监听客户端的连接。我们一般通过在while(true) 循环中服务端会调用 accept() 方法等待接收客户端的连接的方式监听请求,请求一旦接收到一个连接请求,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成, 不过可以通过多线程来支持多个客户端的连接,如下图所示。
伪异步IO(加入线程池)
为了解决同步阻塞I/O面临的一个链路需要一个线程处理的问题,后来有人对它的线程模型进行了优化一一一后端通过一个线程池来处理多个客户端的请求接入,形成客户端个数M:线程池最大线程数N的比例关系,其中M可以远远大于N.通过线程池可以灵活地调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。
总结:
在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
NIO(New I/O)
NIO简介
NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。
它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 **SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。**阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。1)对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;2)对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
NIO的特性/NIO与IO区别
如果是在面试中回答这个问题,我觉得首先肯定要从 NIO 流是非阻塞 IO 而 IO 流是阻塞 IO 说起。然后,可以从 NIO 的3个核心组件/特性为 NIO 带来的一些改进来分析。如果,你把这些都回答上了我觉得你对于 NIO 就有了更为深入一点的认识,面试官问到你这个问题,你也能很轻松的回答上来了。
1)Non-blocking IO(非阻塞IO)
IO流是阻塞的,NIO流是不阻塞的。
Java NIO使我们可以进行非阻塞IO操作。比如说,单线程中从通道读取数据到buffer,同时可以继续做别的事情,当数据读取到buffer中后,线程再继续处理数据。写数据也是一样的。另外,非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
Java IO的各种流是阻塞的。这意味着,**当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。**该线程在此期间不能再干任何事情了
2)Buffer(缓冲区)
IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。
- NIO类库加入Buffer对象,即所有数据都是用缓冲区处理的,在读取数据时,它是直接读到缓冲区中,在写入数据时,斜土数据区中。任何时间访问NIO中的数据,都是通过缓冲区进行操作。
最常用的缓冲区是ByteBuffer,一个ByteBuffer用于操作byte数组。每一种Java基本类型都对应一种缓冲区(除了boolean类型) - 在面向流IO中,,可以将数据直接写入或者将数据直接读到Stream随想中,虽然Stream中也有Buffer开头的扩展类,但是只是流的包装类,还是从流读到缓冲区。
3)Channel (通道)
NIO通过Channel(通道)进行读写。
通道是双向的,可读可写,而流是单向。因为通道只能和Buffer交互,因为Buffer,通道可以异步的读写。
4)Selectors(选择器)
NIO有选择器,而IO没有。
选择器是用于单个县城处理多个通道。
NIO 读数据和写数据方式
NIo中所有的IO都是从Channel(通道)开始的。
- 从通道进行数据读取:创建一个缓冲区,然后请求通道读取数据。
- 从通道进行数据写入:创建一个缓冲区,填充数据,并要求铜带写入数据。
NIO核心组件
三个:
- Channel(通道)
- Buffer(缓冲区)
- Selector(选择器)
NIO体系包含不止包含这三个类,这三个是核心。
为什么大家都不愿意用 JDK 原生 NIO 进行开发呢?
- 变成复杂、变成模型难
- JDK的NIO底层由epoll实现,该实现空轮询bug会导致cpu飙升到100%。
- 如项目过大,自行实现NIO很容易出现各种bug,维护成本也会高。
所以引进Netty会改善了JDK原生NIO所存在的一些问题。
Netty:Netty封装了JDK的NIO,Netty是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务器和客户端。
https://www.jianshu.com/p/a4e03835921a
AIO(Asynchronous I/O)
AIO是NIO2,即在java7中引入NIO的改进版NIO2,踏实异步非阻塞的IO模型。异步IO是基于事件和回调记住实现。也就是引用操作之后会直接返回,不会阻塞等待,当后台处理完,操作系统会通知相应的线程进行后续的操作。
除了AIO其他的IO类型都是同步的。
Linux的五种IO模型
Java语言中的BIO、NIO、AIO是对操作系统中的各种IO模型的封装。
在Linux(UNIX)操作系统中,共有五种IO模型
IO指的是文件的输入和输出。
例如:一次磁盘文件读取为例,我们要读的文件在磁盘上,目的是读取这个文件到内存上,即数据从硬盘中读取到用户空间中。
阻塞IO模型
阻塞 I/O 是最简单的 I/O 模型,一般表现为进程或线程等待某个条件,如果条件不满足,则一直等下去。条件满足,则进行下一步操作。
非阻塞IO模型
应用进程与内核交互,目的未达到之前,不再一味的等着,而是直接返回。然后通过轮询的方式,不停的去问内核数据准备有没有准备好。如果某一次轮询发现数据已经准备好了,那就把数据拷贝到用户空间中。
信号驱使IO模型
应用进程在读取文件时通知内核,如果某个 socket 的某个事件发生时,请向我发一个信号。在收到信号后,信号对应的处理函数会进行后续处理。
IO复用模型
这里的IO复用模型,并没有向内核注册信号处理函数,所以,他并不是非阻塞的。
多个进程的IO可以注册到同一个管道上,这个管道会统一和内核进行交互。当管道中的某一个请求需要的数据准备好之后,进程再把对应的数据拷贝到用户空间中。(用到select函数)
IO多路转接是多了一个select函数,多个进程的IO可以注册到同一个select上,当用户进程调用该select,select会监听所有注册好的IO,如果所有被监听的IO需要的数据都没有准备好时,select调用进程会阻塞。当任意一个IO所需的数据准备好之后,select调用就会返回,然后进程在通过recvfrom来进行数据拷贝。
为什么以上四种都是同步的
我们说阻塞IO模型、非阻塞IO模型、IO复用模型和信号驱动IO模型都是同步的IO模型。原因是因为,无论以上那种模型,真正的数据拷贝过程,都是同步进行的。
信号驱动难道不是异步的么? 信号驱动,内核是在数据准备好之后通知进程,然后进程再通过recvfrom操作进行数据拷贝。我们可以认为数据准备阶段是异步的,但是,数据拷贝操作是同步的。所以,整个IO过程也不能认为是异步的。
异步IO模型
应用进程把IO请求传给内核后**,完全由内核去操作文件拷贝**。内核完成相关操作后,会发信号告诉应用进程本次IO已经完成。
五种模型的对比
--------------------------------------------------------------------------有待更新-----------------------------------------------------------------------------------
https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/Java IO与NIO.md