一、java nio介绍
java nio全称java non-blocking IO是jdk1.4以后java新增的非阻塞io,完全可以替代之前的阻塞io。
1.原理及实现
java nio采用reactor(反应器)模式,使用单线程模拟多线程,节省系统线程创建和线程上下文切换所需要的系统资源消耗。增 加了系统吞吐量。nio包含重要概念 通道、缓冲区、选择器。
通道和缓冲区(Channels and Buffers):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
通道类型: FileChannel:从文件中读写数据。 DatagramChannel:能通过UDP读写网络中的数据。 SocketChannel:能通过TCP读写网络中的数据。ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个 SocketChannel。FileChannel比较特殊,它可以与通道进行数据交互, 不能切换到非阻塞模式,套接字通道可以切换到非阻塞模式;
缓冲区 : 本质上是一块可以存储数据的内存,被封装成了buffer对象而已!缓冲区类型:ByteBuffer、MappedByteBuffer 、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer。
选择器:相当于一个观察者,用来监听通道感兴趣的事件,一个选择器可以绑定多个通道;
二、tomcat9中的nio使用
tomcat8之后去掉原来tomcat中支持的bio模式。只支持nio(非阻塞io)和apr(操作系统级别的异步io)模式。说明tomcat开发者认为现在nio的性能在大多数情况下已经至少不低于bio(阻塞io)。之前网上有很多测试在连接数小于1000的时候tomcat的nio模式没有明显的性能提升,甚至还略低于传统的bio模式。这是因为nio优化的性能在线程的资源占用和上下文切换上。如果连接数较少,这种优化就无法体现。在大并发,传统模式需要超多线程的情况下,nio模式的性能才有明显提高。下面我就来总结下tomcat9中nio的实现和使用。
tomcat9中nio的使用主要逻辑在NioEndpoint这个类中。主要有 Acceptor、Poller、SocketProcessor、Excutor等组件参与。来看下他们是如何来实现连接的接入的吧!
首先从Connector这个类来说起,这个类是用来处理连接的。

这是这个组件的启动方法,继续看下protocolHandler.start()这个方法里面。protocolHandler是具体的协议处理器。这里默认应该是http1.1的协议处理器。

这个方法里面首先启动了NioEndPoint组件。然后启动一个超时时间守护线程。这个线程我没有仔细去看应该是监测异步请求的超时。应该属于http协议的实现部分,暂不做关注,直接进入endpoint.start()方法。

继续看下startInternal方法这个方法在具体的实现类中,这里我们看下Nioendpoint的startInternal方法。

看下startAcceptorThreads方法

开始接收请求。那么是如何接受请求的呢。我们进去其中一个AcceptorThreads中看看。我们看下这这个thread中的run方法都干了什么

我们看到,AcceptorThreads中主要是先获取了一个链接,然后调用endpoint的setSocketOptions方法,我们看看setSocketOptions方法里都干了什么。

我们看到setSocketOptions 方法首先包装了下channel,然后就把channel注册进了poller里。那poller是如何监听的channel的呢。我们来看下poller的构建及运行。首先我们看下poller的构建方法。

可以看出来poller只是对java nio包中selector进行了一个包装。调用poller构造方法时。实际上构造了一个selector.我们再来看看注册方法执行了什么?

poller的注册方法只是对socket的channle做了一层封装,然后就注册一个事件。所以tomcat 和javanio相似只是包装了一层哈。
网友评论