nio buffer 用法
NIO的Buffer(缓冲区)本质上是一个内存块,既可以写入数据,也可以从中读取数据。NIO的Buffer类,是一个抽象类,位于java.nio包中,其内部是一个内存块(数组)。NIO的Buffer与普通的内存块(Java数组)不同的是:NIOBuffer对象,提供了一组更加有效的方法,用来进行写入和读取的交替访问。需要强调的是:Buffer类是一个非线程安全类.
1. Buffer类Buffer类是一个抽象类,对应于Java的主要数据类型,在NIO中有8种缓冲区类,分别如下:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer。前7种Buffer类型,覆盖了能在IO中传输的所有的Java基本数据类型。第8种类型MappedByteBuffer是专门用于内存映射的一种ByteBuffer类型。实际上,使用最多的还是ByteBuffer二进制字节缓冲区类型,后面会看到。
2.capacity属性Buffer类的capacity属性,表示内部容量的大小。
一旦写入的对象数量超过了capacity容量,缓冲区就满了,不能再写入了。Buffer类的capacity属性一旦初始化,就不能再改变。原因是什么呢?Buffer类的对象在初始化时,会按照capacity分配内部的内存。在内存分配好之后,它的大小当然就不能改变了。再强调一下,capacity容量不是指内存块byte[]数组的字节的数量。capacity容量指的是写入的数据对象的数量。前面讲到,Buffer类是一个抽象类,Java不能直接用来新建对象。使用的时候,必须使用Buffer的某个子类,例如使用DoubleBuffer,则写入的数据是double类型,如果其capacity是100,那么我们最多可以写入100个double数据。
3.position属性Buffer类的position属性,表示当前的位置。
position属性与缓冲区的读写模式有关。在不同的模式下,position属性的值是不同的。当缓冲区进行读写的模式改变时,position会进行调整。
在写入模式下,position的值变化规则如下:
(1)在刚进入到写模式时,position值为0,表示当前的写入位置为从头开始。
(2)每当一个数据写到缓冲区之后,position会向后移动到下一个可写的位置。
(3)初始的position值为0,最大可写值position为limit–1。当position值达到limit时,缓冲区就已经无空间可写了。
在读模式下,position的值变化规则如下:
(1)当缓冲区刚开始进入到读模式时,position会被重置为0。
(2)当从缓冲区读取时,也是从position位置开始读。读取数据后,position向前移动到下一个可读的位置。(3)position最大的值为最大可读上限limit,当position达到limit时,表明缓冲区已经无数据可读。起点在哪里呢?当新建一个缓冲区时,缓冲区处于写入模式,这时是可以写数据的。数据写入后,如果要从缓冲区读取数据,这就要进行模式的切换,可以使用(即调用)flip翻转方法,将缓冲区变成读取模式。在这个flip翻转过程中,position会进行非常巨大的调整,具体的规则是:position由原来的写入位置,变成新的可读位置,也就是0,表示可以从头开始读。flip翻转的另外一半工作,就是要调整limit属性。
3.limit属性Buffer类的limit属性,表示读写的最大上限。
limit属性,也与缓冲区的读写模式有关。在不同的模式下,limit的值的含义是不同的。在写模式下,limit属性值的含义为可以写入的数据最大上限。在刚进入到写模式时,limit的值会被设置成缓冲区的capacity容量值,表示可以一直将缓冲区的容量写满。在读模式下,limit的值含义为最多能从缓冲区中读取到多少数据。
一般来说,是先写入再读取。当缓冲区写入完成后,就可以开始从Buffer读取数据,可以使用flip翻转方法,这时,limit的值也会进行非常大的调整。具体如何调整呢?将写模式下的position值,设置成读模式下的limit值,也就是说,将之前写入的最大数量,作为可以读取的上限值。在flip翻转时,属性的调整,将涉及position、limit两个属性,这种调整比较微妙,不是太好理解,举一个简单例子:首先,创建缓冲区。刚开始,缓冲区处于写模式。position为0,limit为最大容量。然后,向缓冲区写数据。每写入一个数据,position向后面移动一个位置,也就是position的值加1。假定写入了5个数,当写入完成后,position的值为5。这时,使用(即调用)flip方法,将缓冲区切换到读模式。limit的值,先会被设置成写模式时的position值。这里新的limit是5,表示可以读取的最大上限是5个数。同时,新的position会被重置为0,表示可以从0开始读。
除了前面的3个属性,第4个属性mark(标记)比较简单。就是相当一个暂存属性,暂时保存position的值,方便后面的重复使用position值。下面用一个表格总结一下Buffer类的4个重要属性,参见表3-1。Buffer四个重要属性的取值说明
4.buffer的重要方法
allocate()创建缓冲区,put()写入到缓冲区,flip()翻转,Buffer.clear()从读取模式转换为写入模式
5.buffer的使用基本步骤
总体来说,使用JavaNIOBuffer类的基本步骤如下:
(1)使用创建子类实例对象的allocate()方法,创建一个Buffer类的实例对象。
(2)调用put方法,将数据写入到缓冲区中。
(3)写入完成后,在开始读取数据前,调用Buffer.flip()方法,将缓冲区转换为读模式。
(4)调用get方法,从缓冲区中读取数据。
(5)读取完成后,调用Buffer.clear()或Buffer.compact()方法,将缓冲区转换为写入模式。
本资料收集于Netty、Redis、Zookeeper高并发实战,希望大家购买正版图书