介绍
NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
非阻塞式网络通信模型
传统流是单通道的
- 线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞IO 的空闲时间用于在其他通道上执行 IO操作,所以单独的线程可以管理多个输入和输出通道
- NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端
缓冲区
流 vs 缓冲区
- 流:随着时间到来的数据
- 缓冲区:缓冲作用
- 按键太快
- 磁盘写入操作太多
- 网络请求太多
- 现实模型:理发店
- 缓冲的本质是排队、流的本质是数据
直接缓冲区
- 通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率
- 可以驻留在常规的垃圾回收堆之外
- 直接字节缓冲区还可以通过FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建
非直接缓冲区
通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中
属性与流程
属性
- 容量 (capacity) :不能更改,不能为负。
- 限制 (limit):位于 limit 后的数据不可读写
- 位置 (position):当前要读取或写入数据的索引
- 标记 (mark):是一个索引,标记为position位置。 恢复到标记的position
- 0 <= mark <= position <= limit <= capacity
流程
- 静态方法创建缓存区,进入写准备
- PUT 方法写入,flip方法切换读
- 读完后,clear 为下一次 写循环准备
- 重复读 rewind mark/reset
方法
- Buffer flip():将limit设置为当前position,将position设置为 0,mark设置为-1
- Buffer rewind():将position设为为 0, mark设为-1。可重复读
- Buffer mark():对缓冲区设置mark
- Buffer reset():将位置 position 转到以前设置的 mark 所在的位置
- boolean hasRemaining():判断缓冲区中是否还有元素
- int remaining():返回 position 和 limit 之间的元素个数
- Buffer clear():将limit设为capacity,将position设为0,并将mark设为-1。数据没有清空
- Buffer limit(int n):将设置缓冲区界限为 n, 并返回一个具有新 limit 的缓冲区对象
- int capacity() :返回 Buffer 的 capacity 大小
- int limit() :返回 Buffer 的界限(limit) 的位置
- int position() :返回缓冲区的当前位置 position
- Buffer position(int n) :将设置缓冲区的当前位置为 n , 并返回修改后的 Buffer 对象
String str = "abcde";
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
buf.put(str.getBytes());
buf.flip();
byte[] dst = new byte[buf.limit()];
buf.get(dst, 0, 2);
System.out.println(new String(dst, 0, 2));
System.out.println(buf.position());
//mark() : 标记
buf.mark();
//不可重复读
buf.get(dst, 2, 2);
System.out.println(new String(dst, 2, 2));
System.out.println(buf.position());
//reset() : 恢复到 mark 的位置
buf.reset();
System.out.println(buf.position());
//缓冲区遍历
if(buf.hasRemaining()){
System.out.println(buf.remaining());
}
//5. rewind() : 可重复读
buf.rewind();
System.out.println("-----------------rewind()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//6. clear() : 清空缓冲区. 但是缓冲区中的数据依然存在,但是处于“被遗忘”状态
buf.clear();
System.out.println("-----------------clear()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
System.out.println((char)buf.get());