什么是NIO
java.nio全称java non-blocking IO 也有人称着new io。是指JDK 1.4及以上版本里提供的新api(New IO),为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络。
BIO和NIO的对比
BIO | NIO |
---|---|
面向流(Stream Oriented) | 面向缓冲区(Buffer Oriented) |
阻塞IO(Blocking io) | 非阻塞IO(non blocking io) |
无 | 选择器(Selectors) |
JAVA NIO 3大核心组件
- Buffer
- Channel
- Selector
Buffer
buffer缓冲区,本质上是一个内存块,可以将数据写入这块内存,也可以从这块内存获取数据。
从buffer进行数据写入与读取需要以下4个步骤:
- 将数据写入缓冲区
- 调用buffer.flip()转换为读模式
- 从缓冲区读取数据
- 调用buffer.clear()或则buffer.compact()清除缓冲区
buffer三个重要属性:
- capacity容量:作为一个内存块,buffer上具有固定的大小
- position位置:写模式时代表写数据的位置,读模式时代表读取数据的位置,从写模式切换到读模式时position都会清零,这样就要以从头读了。
- limit限制:写模式时,等于buffer的容量,读取模式下等于写入的数据量
JAVA NIO中buffer定义了以下几个buffer的实现:CharBuffer, ShortBuffer , IntBuffer , LongBuffer , FloatBuffer , DoubleBuffer , ByteBuffer
Bytebuffer提供了两种内存申请方式,DirectByteBuffer(堆外内存)和HeapByteBuffer
(堆内内存)
- HeapByteBuffer: HeapByteBuffer,标准的java类,维护一份byte[]在JVM堆上,创建开销小
- DirectByteBuffer:底层存储在非JVM堆上,通过native代码操作,-XX:MaxDirectMemorySize=,创建开销大
堆外内存的好处:
- 在进行网络IO或则文件IO的时候会比堆内内存少一次拷贝(因为堆内内存在GC的时候会移动对象内存,所以会先拷贝数据到堆外内存上再进行IO)
- GC范围之外,降低了GC压力。实现自动管理,DirectByteBuffer中有一个Cleaner对象,GC前会执行clean方法,触发DirectByteBuffer中定义的Deallocator
建议在性能确实可观的时候才使用堆外内存,分配给大型,长寿命的对象。通过虚拟机参数MaxDirectMemorySize来限制大小,防止耗尽机器内存。
Channel
JAVA NIO中所有的操作始于通道,通道是数据来源或则写入的目的地。
java中channel主要有4个实现:
- FileChannel:文件通道,用于文件的读和写
- DatagramChannel:用于UDP连接的接收和发送
- SocketChannel:用于TCP连接的客户端
- ServerSocketChannel:用于TCP连接的服务端
NIO的读操作就是将数据从channel读取到buffer中进行处理。channel.read(buffer)
NIO的写操作就是将数据从buffer中写入到channel中.channel.write(buffer)
Selector
selector可以检查一个或则多个channel,并确定哪些channel已经准备好进行读或写,实现单线程可以管理多个channel。
一个线程使用selector监听多个channel的不同事件。
事件分别分为:connect 连接,accept 准备就绪,read 读取,write 写入
实现一个selector处理多个channel的核心概念为:事件驱动机制。
通过selector注册对于通道感兴趣的类型,线程通过监听事务来触发相应的代码执行