JAVA NIO工作原理及代码实例分析

简介:本文主要介绍了Java NIO中的Buffer, Channel, Selector的工作原理以及使用它们的若干注意事项,最后是利用它们实现服务器和客户端通信的代码实例。

1. ByteBuffer

1.1直接缓冲区和非直接缓冲区

下面是创建ByteBuffer对象的几种方式

static ByteBuffer

 

allocate(int capacity)

 

static ByteBuffer

 

allocateDirect(int capacity)

 

static ByteBuffer

 

wrap(byte[] array)

 

static ByteBuffer

 

wrap(byte[] array, int offset, int length)

 

allocate方式创建的ByteBuffer对象我们称之为非直接缓冲区,这个ByteBuffer对象(和对象包含的缓冲数组)都位于JVM的堆区。wrap方式和allocate方式创建的ByteBuffer没有本质区别,都创建的是非直接缓冲区。

allocateDirect方法创建的ByteBuffer我们称之为直接缓冲区,此时ByteBuffer对象本身在堆区,而缓冲数组位于非堆区, ByteBuffer对象内部存储了这个非堆缓冲数组的地址。在非堆区的缓冲数组可以通过JNI(内部还是系统调用)方式进行IO操作,JNI不受gc影响,机器码执行速度也比较快,同时还避免了JVM堆区与操作系统内核缓冲区的数据拷贝,所以IO速度比非直接缓冲区快。然而allocateDirect方式创建ByteBuffer对象花费的时间和回收该对象花费的时间比较多,所以这个方法适用于创建那些需要重复使用的缓冲区对象。

1.2重要属性和方法

ByteBuffer对象三个重要属性 position, limit和capacity。其中capacity表示了缓冲区的总容量,始终保持不变,初始时候position 等于 0 , limit 等于 capacity

1) put:向缓冲区放入数据

abstract ByteBuffer

 

put(byte b)

 

ByteBuffer

 

put(byte[] src)

 

ByteBuffer

 

put(byte[] src, int offset, int length)

 

调用put方法前,limit应该等于capacity,如果不等于,几乎可以肯定我们对缓冲区的操作有误。在put方法中0到position-1的区域表示有效数据,position到limit之间区域表示空闲区域。put方法会从position的当前位置放入数据,每放入一个数据position增加1,当position等于limit(即空闲区域使用完)时还继续放入数据就会抛出BufferUnderflowException异常

2)get:从缓冲区读取数据

abstract byte

 

get()

 

ByteBuffer

 

get(byte[] dst)

 

ByteBuffer

 

get(byte[] dst, int offset, int length)

 

在get方法中, 0到position-1的区域表示已读数据,position到limit之间的区域表示未读取的数据。每读取一个数据position增加1,当position等于limit时继续读取数据就会抛出BufferUnderflowException异常。

2)flip :将写模式转换成读模式

public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

3)clear:清空缓冲区,将读模式转换写模式

public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
}

4)compact:保留未读取的数据,将读模式转换写模式

public ByteBuffer compact() {
 
    int pos = position();
    int lim = limit();
    assert (pos <= lim);
    int rem = (pos <= lim ? lim - pos : 0);
 
    unsafe.copyMemory(ix(pos), ix(0), (long)rem << 0);
    position(rem);
    limit(capacity());
    discardMark();
    return this;
 
}

5)mark:保存当前position的位置到mark变量

public final Buffer mark() {
    mark = position;
    return this;
}

6)rest:将position置为mark变量中的值

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/39980f0e5d16638c925b21f6b950f590.html