本文主要讲解bio以及nio的一些问题和知识,会对aio进行简单讲解,但不会深入剖析
我们说熟知的io模型有哪些呢?
- 同步阻塞io
- 同步非阻塞io
- 同步多路复用
- 异步非阻塞io
java的io本身是不具有真正的io操作能力的,当调用io操作时,仍然需要切换到底层做系统去调用真正的io操作才可以实现一次io读取或者写入操作的
这里注意啊,有些地方还有一个说法,是异步阻塞io,这个说法是错误的啊,异步是不会存在阻塞行为的,所以以后听到异步阻塞,你就可以开始怼他了,好了,废话不多说,正文开始!
一,同步阻塞io
什么是同步阻塞io呢,首先声明,我们的全部说法都是建立与单线程模式下的情况,这样更易于理解
我拿一次网络写入操作举例啊:我们首先肯定是先要建立连接,然后再去读取客户端传过来的数据,假如现在过来两次读取请求,需要同一个线程处理,那么第一个请求建立了连接,进到了第二个读取操作,这个时候,客户端的数据还没有发过来,因为这两个方法都是阻塞的(建立连接和读取数据),那么因为第一个请求的读取操作还未处理完,线程就会一直阻塞在读取这,那么第二个线程也无法建立连接,必须等待,第一个请求处理完才可以连接到服务端
从图可知,读取操作时,如果未读取到数据,会在等待数据阶段一直阻塞,直到操作系统拿到数据复制数据后返回数据
二,同步非阻塞io
任然以写入数据为例,与阻塞io不同,非阻塞io假如我们第一个请求还未发过来数据,那么也不会一直阻塞在读取操作,会继续往下走,去建立新的连接,但是也存在弊端,就是,如果不管有没有收到客户端的数据,它都会去读一次数据,这个不同的循环读取,做一些无意义的操作,就将服务器资源浪费掉了,增加了cpu的开销和压力,这个时候就出现了多路复用
从图可知,当未获取到数据时,不会阻塞,而是继续往下执行,连接读取的操作,但是会造成资源浪费 ,等待数据阶段不会阻塞,但是仍然复制数据时阻塞
三,多路复用
其实多路复用仍然是基于同步非阻塞模型的,只不过在nio的基础上引入了select模型,通过它可以做到同时处理多个channel通道的操作,通过将通道绑定到selector上,通过返回的selectkey绑定具体的操作事件,将事件全部存储到selector中,通过select()方法进行阻塞,假如目前没有操作,就会一直阻塞,事件过来时,继续通过selectkey去获取到进来的所有事件,然后去判断具体的操作事件,执行的具体的操作
四,异步非阻塞io
其实就是我们所熟知的aio,这个东西怎么说呢,目前的linux上对异步的支持不是那么好,虽然在2.6引入了异步的概念,但实际上还是基于多路复用的一个模拟罢了,并不是真正意义上的异步io,而真正实现aio的只有windows系统,微软在windows上通过IOCP的方式对异步做了真正意义的实现,但是大家都懂,大部分的java程序,都运行在linux上,所以,aio到目前为止,java的支持并不是特别好,事实上之前netty有通过2.6引入的异步模型做过实现,但是发现netty5的版本性能并未提升,反而增加了维护成本,所以在维护了一段时间后,果断废弃掉了5的版本,所以目前netty的主要版本还是4
异步io的实质:线程不去自己获取结果,而是有其他线程送结果(所以至少两个线程)
这个图可以很清晰的明白aio的本质