上一篇讲到无法从根本上解决阻塞问题,但是在jdk1.4以后引入NIO类库以后,成功解决掉了这个问题。
在传统BIO中我们对每一个请求都需要一个处理,但是引入NIO以后我们可以一个线程处理多个请求。
在介绍NIO以前先介绍一些概念:
缓冲区Buffer
Buffer是一个对象,在面向流的IO中可以将数据直接读/写到Stream对象中。在NIO中所有的数据都是用缓冲区来做处理的。
事实上,缓冲区就是一个数组,但是它提供了数据的结构化访问即维护读写位置等信息。
NIO为每一个基本类型(除boolean)都提供了一个缓冲区:
他们都继承Buffer这个类,通过查看源码,Buffer有如下属性:
private int mark = -1; //标记,标记后的索引位置,可以通过reset()方法修改position到该位置,mark的位置要<=poition
private int position = 0; //下一个要读取的位置
private int limit; //限制,按照索引来,limit之后的不能修改,limit范围内的可以进行读写操作
private int capacity; //Buffer中最大容量,不能为负
常用方法:
//构造方法
Buffer(int mark, int pos, int lim, int cap) { // package-private
if (cap < 0)
throw new IllegalArgumentException("Negative capacity: " + cap);
this.capacity = cap;
limit(lim);
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException("mark > position: ("
+ mark + " > " + pos + ")");
this.mark = mark;
}
}
//通过构造方法,可以看出容量不能为负,并且mark>=0,且<position;
//设置位置
public final Buffer position(int newPosition) {
if ((newPosition > limit) || (newPosition < 0))
throw new IllegalArgumentException();
position = newPosition;
if (mark > position) mark = -1;
return this;
}
//position的位置必须要limit范围内,并且不能小于0,如果mark>新的postion,将mark置为-1
//设置约束
public final Buffer limit(int newLimit) {
if ((newLimit > capacity) || (newLimit < 0))
throw new IllegalArgumentException();
limit = newLimit;
if (position > limit) position = limit;
if (mark > limit) mark = -1;
return this;
}
//要求liimit小于容量,且poition>新limit时,将position设为limit的位置,同时mark也不能大于limit
//将postion还原为position
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
//清空Buffer
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
//翻转缓冲区(读取数据的时候使用),读取完之后为写入做好准备
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
//这样做的目的是为了读出有效数据,limit为长度,从position开始读取
//重置,为重新读取做好准备
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
当然在他的子类中也增加了一些方法(以IntBuffer为例):
//属性
final int[] hb; // 用数组进行存储
final int offset; //起始位置
boolean isReadOnly; //是否只读标志
//常用方法
//创建方法:
public static IntBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapIntBuffer(capacity, capacity);
}
//这里数通过HeapIntBuffer去初始化的
//添加数据
public IntBuffer put(IntBuffer src) {
if (src == this)
throw new IllegalArgumentException();
if (isReadOnly())
throw new ReadOnlyBufferException();
int n = src.remaining();
if (n > remaining())
throw new BufferOverflowException();
for (int i = 0; i < n; i++)
put(src.get());
return this;
}
//读取数据
public IntBuffer get(int[] dst, int offset, int length) {
checkBounds(offset, length, dst.length);
if (length > remaining())
throw new BufferUnderflowException();
int end = offset + length;
for (int i = offset; i < end; i++)
dst[i] = get();
return this;
}
//比较方法
public boolean equals(Object ob) {
if (this == ob)
return true;
if (!(ob instanceof IntBuffer))
return false;
IntBuffer that = (IntBuffer)ob;
if (this.remaining() != that.remaining())
return false;
int p = this.position();
for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
if (!equals(this.get(i), that.get(j)))
return false;
return true;
}
使用案例:
IntBuffer buffer = IntBuffer.allocate(10);
buffer.put(10);
buffer.flip();
System.out.println(buffer.position()+" "+buffer.capacity()+" "+buffer.limit());
System.out.println(buffer.get(0));