凡科建设网站怎么保存,做网站绿色和什么颜色搭配,建筑公司加盟开分公司,企业网址怎么制作NIO简介
高性能的Java通信#xff0c;离不开Java NIO组件#xff0c;现在主流的技术框架或中间件服务器#xff0c;都使用了Java NIO组件#xff0c;譬如Tomcat、 Jetty、 Netty、Redis、RabbitMQ等的网络通信模块。在1.4版本之前#xff0c; Java IO类库是阻塞式IO…NIO简介
高性能的Java通信离不开Java NIO组件现在主流的技术框架或中间件服务器都使用了Java NIO组件譬如Tomcat、 Jetty、 Netty、Redis、RabbitMQ等的网络通信模块。在1.4版本之前 Java IO类库是阻塞式IO从1.4版本开始引进了新的异步IO库被称为Java New IO类库简称为Java NIO。 称“老的”阻塞式Java IO为OIOOld IO。总体上说 NIO弥补了原来面向流的OIO同步阻塞的不足它为标准Java代码提供了高速的、面向缓冲区的IO。 学习NIO最主要的要理解Channel通道、Selector选择器、Buffer缓冲区三个核心组件。
在Java中 NIO和OIO的区别主要体现在三个方面: OIO是面向流Stream Oriented的 NIO是面向缓冲区Buffer Oriented的。 如何理解呢非常简单假设两个计算机的进程建立了通信OIO的 read() 操作总是以输入流式的方式顺序地读取读取一个或多个字节期间要么读要么不读不能随意乱序读取。而写数据也只能往输出流写入数据。输入流和输出流是单向数据传输的。而NIO引入了Channel通道和Buffer缓冲区的概念。面向缓冲区的读取和写入都是与Buffer进行交互。用户程序只需要从通道中读取数据到缓冲区中或将数据从缓冲区中写入到通道中。 NIO不像OIO那样是顺序操作可以随意地读取Buffer中任意位置的数据可以随意修改Buffer中任意位置的数据。如下图所示通道处于应用层所有的通信都需要经过Channel通道 OIO的操作是阻塞的而NIO的操作是非阻塞的。 OIO阻塞 当线程执行到read()和write()和连接服务器时的方法期间如果没有对应的IO事件发生客户端发送了连接请求、客户端发数据过来了则一直在这些代码处等待期间不做任何事情线程挂起阻塞。直到发生了相应的IO事件才继续往下执行。并且如果还有其他的客户端触发了不是导致阻塞的IO事件也可能被阻塞。假设有两个客户端A和B服务器伪代码如下所示当没有客户端建立连接时则下面代码阻塞在第2行假设此时A请求连接那么下面代码就执行第2行然后阻塞在第3行。此时B也请求建立连接这时候B是无法连接的因为服务器代码阻塞在第3行。如果此时A发送了一个消息那么下面程序继续执行获取到A发生过来的消息msg。程序继续执行到第2行如果因为B还在请求直到这个时候B才能连接上服务器程序。这个例子就是OIO阻塞。 // OIO阻塞伪代码先建立连接在读取客户端发来的数据的代码
1 while(true){
2 sc ssc.accept() // 接受客户端连接阻塞方法
3 msg sc.read() // 读取客户端发送过来的数据阻塞方法
4 }NIO非阻塞 NIO的非阻塞实现方法是IO多路复用技术通过selector来监测事件如果没有事件发生则进行阻塞如果有IO事件发生则获取到对应的事件处理对应的事件即可。首先A、B客户端没有连接时下面程序执行到第2行进行阻塞因为没有IO事件发生如果此时A发起了连接则程序执行到第5行代码建立连接如果此时B突然也请求连接下面代码因为没有被阻塞经过10纳秒左右就能运行到第2行代码然后发现B客户的请求连接事件于是继续往下执行同样执行到第5行代码。如果B请求连接的同时A突然发生了消息呢那么没关系events中有两个事件通过for循环都能处理A的消息发生请求会在第7行代码处理掉。下面的代码只是NIO的伪代码实际上用法有一点点语法上的区别逻辑是这样的。可以看见NIO是不会阻塞其他客户端的事件的一般阻塞指的是较长时间的等待例如1秒或者以上下面也是单线程的服务器代码。如果你非要说10纳秒也是阻塞那么下面的代码也确实无法0秒响应实际上世界上也不存在这样的代码。什么是阻塞我相信你已经有了自己的认知了 // NIO非阻塞伪代码先建立连接在读取客户端发来的数据的代码
1 while(true){
2 events selector.select() // 没有事件线程阻塞有事件则接着往下运行
3 for(E e : event){
4 if(e是请求事件){
5 e.connect();
6 }else if (e是读事件){
7 msg e.read();
8 }....
9 }
10 }OIO没有选择器 Selector概念而NIO有选择器的概念。 NIO技术的实现 是基于底层的IO多路复用技术实现的比如在Windows中需要select多路复用组件的支持在Linux系统中需要select/poll/epoll多路复用组件的支持。 所以NIO的需要底层操作系统提供支持。而OIO不需要用到选择器selector相信上面的NIO伪代码让你见识到了selector的威力
到这里你已经基本直到了NIO有多么牛了吧但是还不够前辈们的核心思想学习还刚刚开始接下来需要学习非常核心的NIO类库的三大组件Channel通道、Buffer缓冲区、Selector选择器。
Channel通道
Channel的角色和OIO中的Stream(流)是差不多的。 在OIO中同一个网络连接会关联到两个流一个输入流 Input Stream另一个输出流Output Stream Java应用程序通过这两个流不断地进行输入和输出的操作。在NIO中一个网络连接使用一个Channel 通道 表示所有的NIO的IO操作都是通过连接通道完成的。一个通道类似于OIO中的两个流的结合体既可以从通道读取数据也可以向通道写入数据。Channel和Stream的一个显著的不同是 Stream是单向的譬如InputStream是单向的只读流 OutputStream是单向的只写流 而Channel是双向的既可以用来进行读操作又可以用来进行写操作。如下图所示 NIO中的Channel的主要实现有
FileChannel 用于文件IO操作DatagramChannel 用于UDP的IO操作SocketChannel 用于TCP的传输操作ServerSocketChannel 用于TCP连接监听操作
Selector选择器
首先回顾一下IO多路复用指的是一个进程/线程可以同时监视多个socket连接一旦其中的一个或者多个连接可读或者可写该监听进程/线程能够进行IO事件的查询。在Java应用层面Selector 选择器可以理解为一个IO事件的监听与查询器。通过选择器一个线程可以查询多个通道的IO事件的就绪状态。什么是IO事件呢表示通道某种IO操作已经就绪、或者说已经做好了准备。例如如果一个新Channel连接建立成功了就会在Server Socket Channel上发生一个IO事件代表一个新连接一个准备好这个IO事件叫做“接收就绪”事件。 再例如 一个Channel通道如果有数据可读就会发生一个IO事件代表该连接数据已经准备好这个IO事件叫做 ―“读就绪”事件。Java NIO将NIO事件进行了简化只定义了四个事件这四种事件用SelectionKey的四个常量来表示
SelectionKey.OP_CONNECTSelectionKey.OP_ACCEPTSelectionKey.OP_READSelectionKey.OP_WRITE
Selector本质就是去查询这些IO就绪事件的从编程实现维度来说 IO多路复用编程的第一步是把通道Channel注册到选择器中第二步则是通过选择器Selector所提供的事件查询select方法这些注册的通道是否有已经就绪的IO事件例如可读、可写、网络连接完成等。由于一个选择器只需要一个线程进行监控所以我们可以很简单地使用一个线程通过选择器去管理多个连接通道。与OIO相比 NIO使用选择器的最大优势系统开销小系统不必为每一个网络连接文件描述符创建进程/线程从而大大减小了系统的开销。总之 通过Java NIO可以达到一个线程负责多个连接通道的IO处理 这是非常高效的。这种高效恰恰就来自于Java的选择器组件Selector以及其底层的操作系统IO多路复用技术的支持。
缓冲区Buffer
应用程序通过缓冲区与通道建立数据读写交互Buffer顾名思义缓冲区实际上是一个容器一个连续数组。 Channel提供从文件、网络读取数据的渠道但是读写的数据都必须经过Buffer。 如下图所示 所谓通道的读取就是将数据从通道读取到缓冲区中所谓通道的写入就是将数据从缓冲区中写入到通道中。缓冲区的使用是面向流进行读写操作的OIO所没有的也是NIO非阻塞的重要前提。Buffer类是一个抽象类对应于Java的主要数据类型在NIO中有8种缓冲区类分别如下 ByteBuffer、 CharBuffer、 DoubleBuffer、 FloatBuffer、 IntBuffer、 LongBuffer、 ShortBuffer、MappedByteBuffer。 不同的Buffer子类其能操作的数据类型能够通过名称进行判断比如IntBuffer只能操作Integer类型的对象。 最常用的是ByteBuffer。如ByteBuffer子类就拥有一个byte[]类型的数组成员final byte[] hb作为自己的读写缓冲区数组的元素类型与Buffer子类的操作类型相互对应。那么在接下来的博文中将介绍Buffer具体的用法。
总结
NIO的知识体系就是围绕Buffer缓冲区、 Channel通道、Selector选择器三大核心组件的下面学习只需要学习这三个核心组件的用法即可最后将结合代码举例说明 经典神书推荐《Java高并发核心编程系列》——尼恩