深入分析NIO原理及思想(一)——Java NIO 介绍以及产生原因分析

    任何事物都有其产生的原因。如果传统的io可以解决所有的问题,那么NIO则不会产生。也不会又更后面的AIO(NIO2);

    那么传统的IO模型,即BIO有什么缺点呢。既然他叫BIO,也就是blocking IO , 翻译过来就是阻塞式IO。和非阻塞式IO(NIO),java non-blocking IO。形成鲜明对比。

    即BIO阻塞,NIO不阻塞。那什么是阻塞呢?阻塞,即线程的阻塞,java线程的阻塞状态有很大的一部分是因为使用了BIO导致的。BIO在执行read()方法的时候,会做什么?干等着,就是干等着,等到地老天荒,一直到有人在流中,写了数据,他read到,阻塞的状态解除。除非链接断开,线程关闭,等异常状态,否则,解除阻塞的唯一的方法,就是流里面被写入的数据,他可以read到。

    显而易见,如果是本地数据,没有发生异常的情况下,流里面的数据应该是及时写入的。但在网络应用的时候,进行远程io时,并不知道对面的数据什么时候到达,而我的线程,什么也做不了,只能干等着,无疑,效率是低下的。

    就好像我给你打了个电话,我问你在吗,然后等你的回复,结果,你吃晚饭去了,电话却没有挂(连接建立没有断开),而我肚子很饿(线程上面还有代码需要执行),却只能干等着你给我的回复(执行read方法线程阻塞了),对我而言,无疑是一个浪费。这样的模型,应对现代互联网的大并发,无疑是不合适的。但是对于VIP来讲,这样效率是最高的,因为我的线程始终在等你,我的程序用户量极小,且对性能要求极高的情况的,可以尝试使用。

    对于上述的接了电话就去吃饭的恶劣客户,我们基于BIO也是有处理方法的,也就是设置一个超时,一段时间流中没有被写入,线程阻塞一段时间,那就断开连接,当客户端有需要的时候重新建立连接。但是需要注意,建立连接是一个非常浪费时间的事情。而且不能用连接池的方式优化,因为你不知道客户端在哪,无法预先创建连接,也是一个不现实的想法。

    基于此问题,在java1.4版本,便引入了几个新的包:

   

java.nio  主要是各种Buffer类
java.nio.channels 主要是各种channel,
java.nio.channels.spi 用于选择器和可选择通道的服务提供者类
java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。
java.nio.charset.spi charset 包的服务提供者类。
    这几个包就构成了JavaNIO的核心机制,主要是由各种Buffer(缓冲区),Channel(通道)以及Selector(多路复用器)和Charset(字符转换器)构成的。
    考虑下,如果让你自己实现一套机制,让io不再处于阻塞状态,你该如何去操作?

    出于一个很简单的想法,无论多少客户端,都可以连接到我的这个处理线程上(注册给Selector),我去轮询,问问谁有东西写进来了(channel通道有数据),我去读取(读取到缓冲区buffer),于是一个线程便可以处理,多个客户端的io需求了。那我的线程就不会被阻塞。更聪明的人会想到,有消息进来了,自动通知我,哪个通道就绪,我去处理岂不是更好,连轮询都不用了。这是就是AIO,异步非阻塞的IO,也叫NIO2。其中的异步,以后再谈,浅显看来,认为是OS(操作系统去完成具体IO),java虚拟机做自己的事情,为异步(注:说法不准确)。

    下面我们就需要谈谈,NIO的三个核心,Buffer,Channel,以及Selector。



 



你可能感兴趣的:(java,nio)