本次开始NIO网络编程,之前已经说过BIO,对于阻塞IO里面的问题一定有了清晰的认识,在JDK1.4版本后,提供了新的JAVA IO操作非阻塞API,用意替换JAVA IO 和JAVA NetWorking相关的API。NIO其实有个名称叫new IO。
(一)NIO
介绍
java.nio全称java non-blocking IO(实际上是 new io),是指JDK 1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络。
HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。
三大核心组件
高性能网络编程的基础组件,Buffer缓存区、Channel 通道、Selector 选择器。
(二) Buffer缓存区
介绍
缓存区本质上是一个可以写入数据的内存块(类似数组),然后可以再次读取。此内存块包含在NIO Buffer 对象中,该对象提供了一组方法,可以更轻松地使用内存块。
相比较直接对数组的操作。Buffer API 更加容易操作和管理。
使用Buffer进行数据写入与读取,需要进行如下四个步骤
将数据写入缓冲区。
调用buffer.flip(),转换为读取模式。
缓冲区读取数据。
调用buffer.clear() 或 buffer.compact() 消除缓冲区
Buffer工作原理
BUffer三个重要属性,通过完成了数组的封装。
1.capacity 容量:作为一个内存块,Buffer具有一定的固定大小,也称为【容量】。
2.position 位置:写入模式时代表写数据的位置。读取模式时代表读取数据的位置。
3.limit 限制:写入模式,限制等于buffer的容量,读取模式下,limit等于写入的数据量。
源码
ByteBuffer 内存类型
ByteBuffer 为性能关键型代码提供了直接内存(direct堆外)和非直接内存(heap堆)两种实现,堆外内存获取的方式
好处
进行网络IO 或者 文件IO时比heapBuffer 少一次拷贝,(file/socket —— OS memory —— jvm heap )GC会移动对象内存,在写file 或 socket的过程中,JVM的实现中,会先把数据复制到堆外,在进行写入。
GC范围之外,降低GC压力,但实现了自动管理。DirectByteBuffer 中 有一个Cleaner 对象(PhantomReference) ,Cleaner被GC前会执行clean 方法,触发DirectByteBuffer 中定义Deallocator
建议
性能确实可观的时候才去使用,分配给大型,长寿命(网络传输,文件读写场景)
通过虚拟机参数MaxDirectMemorySize限制大小,防止耗尽整个机器的内存,在JVM之外的内存无法监控。
(三)Channel 通道
介绍
Channel的API 涵盖了UDP、TCP网络和文件IO,FileChannel,DatagramChannel,SocketChannel,ServerSocketChannel。
和标准IO Stream操作的区别
在一个通道内进行读取和写入stream通常是单向的(input 或 output),可以非堵塞读取和写入通道,通道中读取或写入缓冲区。
SocketChannel
SocketChannel用于建立TCP网络连接,类似java.net.Socket。有两种创建socketChannel形式
1.客户端主动发起和服务器的连接
2.服务器获取的新连接
write写
在尚未写入任何内容时可能就返回了。需要在循环中调用write()
read读
read() 方法可能直接返回而根本不读取任何数据,根据返回的int值判断读取了多少字节。
ServerSocketChannel
ServerSocketChannel 可能监听新建立的TCP连接通道,类似ServerSocket。
ServerSocketChannel.accepta()
如果该通道处于飞度赛模式,那么如何没有挂起的连接,该方法将立即返回null。必须检查返回的SocketChannel是否为null。
源码
(四)Select选择器
介绍
Selector 是一个Java NIO 组件,可以检查一个或多个NIO通道,并确定哪些通道已准备好进行读取或写入,实现单个线程可以管理多个通道,从而管理或多个网络连接。
selector 监听多个 channel的不同事件
Connect 连接(SelectionKey.OP_CONNECT)
Accept 准备就绪(OP_ACCEPT)
Read 读取(OP_READ)
Write 写入(OP_WRITE)
selector 选择器
一个线程处理多个通道的核心概念理解:事件驱动机制。
非堵塞的网络通道下,开发者通过Selector注册对于通道感兴趣的事件类型,线程通过监听事件来触发响应的代码执行(最底层hi操作系统的多路复用机制)
源码
NIO 和 BIO 的区别
NIO Reactor的方式
PS:NIO为开发者提供了功能丰富及强大的IO处理API,但是在应用开发的过程中,直接使用JDK提供的API,比较繁琐,而且要想将性能进行提升,光有NIO还是不够的,还需要将多线程技术与之结合起来。因为网络编程本身的复杂性,以及JDK API开发的使用难度较高,所以开源社区中,涌出来很多的JDK NIO进行封装了,增强后的网络编程框架,例如:Netty、Mina等。