总结一下关于 NIO 的知识。(jdk1.7)
NIO(Non-blocking IO 或称为 New IO)是JavaSE1.4 出的新特性,就我当前的了解,它优化了 IO 性能,并支持非阻塞 IO 操作。
对于 IO 性能的优化,主要集中在 Channel 和 Buffer 上,今天先说Buffer。
看一眼 接口Buffer 的源码:
Buffer.java
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
Buffer(int mark, int pos, int lim, int cap) { // package-private
this.capacity = cap;
limit(lim);
position(pos);
...
}
初始化主要是对4个int类型的变量赋初值。
再看一眼一个具体实现类 ByteBuffer 的源码,
ByteBuffer.java
ByteBuffer(int mark, int pos, int lim, int cap, byte[] hb, int offset) // package-private
{
super(mark, pos, lim, cap);
this.hb = hb;
this.offset = offset;
}
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
// HeapByteBuffer 继承自 ByteBuffer
}
可以看到,ByteBuffer缓冲区的底层是用 byte[] 实现的,并且ByteBuffer的构造方法并没有公开,我们可以通过 ByteBuffer.allocate( int capacity ) 来获取一个容量为 capacity 的 ByteBuffer。
来画一下这个 Buffer,先不考虑 mark,结合Buffer构造中能看到的属性,并且有 position(位置) <= limit(极限) <= capacity(容量),那一个容量为8的 Buffer 大概就是这样:
要了解这几个数值的作用,先看下面的代码:
这里的 fileChannel.read(byteBuffer) 的作用是把 fileChannel 中的数据写入 byteBuffer。
ByteBuffer byteBuffer = ByteBuffer.allocate(8);
int bytesRead = fileChannel.read(byteBuffer);
while (bytesRead != -1) {
byteBuffer.flip();
while(byteBuffer.hasRemaining()){
System.out.print((char) byteBuffer.get());
}
byteBuffer.clear(); //清空缓冲区
bytesRead = fileChannel.read(byteBuffer);
}
能进入外层 while 循环,说明 byteBuffer 中被写入了数据。内层 while 循环的作用是 输出 byteBuffer 中的读到到数据,byteBuffer.get() 在子类 HeapByteBuffer 中实现
return hb[ix(nextGetIndex())];
返回下一单元的数据。
byteBuffer.clear():极限设为容量,位置设为0,相当于清空了缓冲区,便于下次读入数据。
我们假设本次读入了5个 byte 的数据,Buffer那大概就是这样:
所以,byteBuffer.flip();
的作用是什么呢?
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
flip 之后
显而易见,flip标识出了本次读入数据的起止位置。也就是准备好了数据读取的位置和上限,get方法是从position开始的,这时使用 while{buffer.get()}
就可以顺利读取了。并且,如果上一次写入了8个数据,本次写入了5个,那么本次只能读取到5个,而不能读取到上次写入后未被覆盖的3个数据。
另:
1. 也可用 ByteBuffer.allocateDirect(int capacity) 得到 ByteBuffer,速度快但有其他代价;
2. get()相对读,get(int index)为绝对读;相应的 put()相对写,put(int index)绝对写。均只能读写一个byte。
3. Buffer 的其他实现还有:ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer、CharBuffer、MappedByteBuffer。
明天说Channel。