NIO
NIO是Java继传统的阻塞IO后推出的新的IO模型,是一种同步非阻塞的模型,还有一种异步IO是叫做NIO2(AIO),这种IO是IO模型中异步IO的实现,但是在Linux上由于epoll支持的不太好,所以并未广泛使用
IO模型
IO模型一共有五种
- 阻塞式IO
- 非阻塞式IO
- 异步IO
- 信号量IO
- IO复用
Java的BIO属于阻塞式IO,NIO属于非阻塞式(需要不断轮询),AIO属于异步IO(基于事件异步回调)
NIO的三个组成部分
- Channel
- FileChannel: 从文件中读写数据
- DatagramChannel: 通过 UDP 读写网络中数据
- SocketChannel: 通过 TCP 读写网络中数据
- ServerSocketChannel:作为服务端监听SocketChannel
- Buffer
- ByteBuffer
- CharBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
一般常用ByteBuffer
- Selector
ByteBuffer的常用方法
分配空间
方法allocate()
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw createCapacityException(capacity);
return new HeapByteBuffer(capacity, capacity, null);
}
在堆Heap中分配一个缓冲区,用于读写数据,读写效率较低,受到GC的影响
e.g
var buffer = ByteBuffer.allocate(16);
方法allocateDirect()
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
在用户直接内存空间分配一个缓冲区,用于读写数据,读写效率高(零拷贝的基础),不会收到GC影响,分配的效率低,有内存泄露的风险
e.g
var directBuffer = ByteBuffer.allocateDirect(16);
写入数据
方法put()
public abstract ByteBuffer put(byte b);
这里的实现类为
Channel的的read()
public abstract int read(ByteBuffer dst) throws IOException;
读取数据
get()
public abstract byte get();
get()方法会让position读指针向后走,如果想重复读取数据
- 可以调用rewind方法将position重新置为0
- 调用get(int i)方法获取索引i的内容,他不会移动读指针
Channel的write()
public abstract int write(ByteBuffer src) throws IOException;
e.g
public class TestByteBufferRead {
public static void main(String[] args) {
//
var buffer = ByteBuffer.allocate(10);
buffer.put(new byte[] {'a', 'b', 'c', 'd'});
buffer.flip();
// 从头开始读
/* buffer.get(new byte[4]);
debugAll(buffer);
buffer.rewind();
buffer.get(new byte[4]);
debugAll(buffer);*/
// mark & reset
// mark 做一个标记,记录position位置,reset是将position重置到mark的位置
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
buffer.mark();
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
buffer.reset();
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
// get(i) 不会改变读索引的位置
System.out.println((char) buffer.get(3));
debugAll(buffer);
}
Q.E.D.