java 缓存Buffer学习

来源:互联网 发布:java ojdbc6 编辑:程序博客网 时间:2024/06/16 03:00
Buffer缓冲区是原始特定类型数据的容器。
A container for data of a specific primitive type.
Buffer缓冲区是特定原始类型的线性、有限元素序列。 没有boolean类型的。除了它的内容外,缓冲区的基本属性是它的容量、极限和位置:

A buffer's capacity is the number of elements it contains. The capacity of a buffer is never negative and never changes.

A buffer's limit is the index of the first element that should not be read or written. A buffer's limit is never negative and is never greater than its capacity.

A buffer's position is the index of the next element to be read or written. A buffer's position is never negative and is never greater than its limit.


Mark和Reset
mark() : Sets this buffer's mark at its position . 调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置
resets() : this buffer's position to the previously-marked position.


变量大小
The following invariant holds for the mark, position, limit, and capacity values:

0 <= mark <= position <= limit <= capacity

A newly-created buffer always has a position of zero and a mark that is undefined. The initial limit may be zero, or it may be some other value that depends upon the type of the buffer and the manner in which it is constructed. Each element of a newly-allocated buffer is initialized to zero.


Clearing, flipping, and rewinding

除了访问方法之外,还有一下方法对 position, limit, 和 capacity values 和marking and resetting 进行操作:
clear() makes a buffer ready for a new sequence of channel-read or relative put operations: It sets the limit to the capacity and the position to zero.
flip() makes a buffer ready for a new sequence of channel-write or relative get operations: It sets the limit to the current position and then sets the position to zero.
rewind() makes a buffer ready for re-reading the data that it already contains: It leaves the limit unchanged and sets the position to zero.


只读buffers


每个缓冲区都可读,但并非每个缓冲区都是可写的。每个缓冲区类突变方法被指定为可选操作,将抛出一个ReadOnlyBufferException例外,当调用在只读缓冲区。只读缓冲区不允许其内容更改,但它的标记、位置和限制值是可变的。是否一个缓冲区是只读的可以通过调用其IsReadOnly法测定。
线程安全


Buffers在多线程中不是线程安全的。在多线程中访问需要自己做同步控制。



Buffer 类是 java.nio 的构造基础。一个 Buffer 对象是固定数量的数据的容器,其作用是一个存储器,或者分段运输区,在这里,数据可被存储并在之后用于检索。缓冲区可以被写满或释放。对于每个非布尔原始数据类型都有一个缓冲区类,即 Buffer 的子类有:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer 和 ShortBuffer,是没有 BooleanBuffer 之说的。尽管缓冲区作用于它们存储的原始数据类型,但缓冲区十分倾向于处理字节。非字节缓冲区可以在后台执行从字节或到字节的转换,这取决于缓冲区是如何创建的。 


Buffer
ByteBuffer
ByteOrder
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
MappedByteBuffer  //MappedByteBuffer是直接字节缓冲,内容是文件内存映射区域。通过FileChannel.map 方法创建,
ShortBuffer



缓冲区的四个属性 
        所有的缓冲区都具有四个属性来提供关于其所包含的数据元素的信息:
容量(Capacity):
缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变。
上界(Limit):
缓冲区的第一个不能被读或写的元素。缓冲创建时,limit 的值等于 capacity 的值。假设 capacity = 1024,我们在程序中设置了 limit = 512,说明,Buffer 的容量为1024,但是从 512 之后既不能读也不能写,因此可以理解成,Buffer 的实际可用大小为 512。
位置(Position):
下一个要被读或写的元素的索引。位置会自动由相应的 get() 和 put() 函数更新。 这里需要注意的是positon的位置是从0开始的。
标记(Mark):
一个备忘位置。标记在设定前是未定义的(undefined)。使用场景是,假设缓冲区中有 10 个元素,position 目前的位置为 2(也就是如果get的话是第三个元素),现在只想发送 6 - 10 之间的缓冲数据,此时我们可以 buffer.mark(buffer.position()),即把当前的 position 记入 mark 中,然后 buffer.postion(6),此时发送给 channel 的数据就是 6 - 10 的数据。发送完后,我们可以调用 buffer.reset() 使得 position = mark,因此这里的 mark 只是用于临时记录一下位置用的。
请切记,在使用 Buffer 时,我们实际操作的就是这四个属性的值。我们发现,Buffer 类并没有包括 get() 或 put() 函数。但是,每一个Buffer 的子类都有这两个函数,但它们所采用的参数类型,以及它们返回的数据类型,对每个子类来说都是唯一的,所以它们不能在顶层 Buffer 类中被抽象地声明。它们的定义必须被特定类型的子类所遵从。若不加特殊说明,我们在下面讨论的一些内容,都是以 ByteBuffer 为例,当然,它当然有 get() 和 put() 方法了。 


相对存取和绝对存取


public abstract class ByteBuffer extends Buffer implements Comparable { 
// This is a partial API listing
public abstract byte get( );  
public abstract byte get (int index);  
public abstract ByteBuffer put (byte b);  
public abstract ByteBuffer put (int index, byte b); 

        来看看上面的代码,有不带索引参数的方法和带索引参数的方法。不带索引的 get 和 put,这些调用执行完后,position 的值会自动前进。当然,对于 put,如果调用多次导致位置超出上界(注意,是 limit 而不是 capacity),则会抛出 BufferOverflowException 异常;对于 get,如果位置不小于上界(同样是 limit 而不是 capacity),则会抛出 BufferUnderflowException 异常。这种不带索引参数的方法,称为相对存取,相对存取会自动影响缓冲区的位置属性。带索引参数的方法,称为绝对存取,绝对存储不会影响缓冲区的位置属性,但如果你提供的索引值超出范围(负数或不小于上界),也将抛出 IndexOutOfBoundsException 异常。 
◇  wrap
wrap(byte[] array) 这个缓冲区的数据会存放在byte数组中,bytes数组或buff缓冲区任何一方中数据的改动都会影响另一方。其实ByteBuffer底层本来就有一个bytes数组负责来保存buffer缓冲区中的数据,通过allocate方法系统会帮你构造一个byte数组
wrap(byte[] array,
 int offset, int length)
在上一个方法的基础上可以指定偏移量和长度,这个offset也就是包装后byteBuffer的position,而length呢就是limit-position的大小,从而我们可以得到limit的位置为length+position(offset)


翻转 
        我们把 hello 这个串通过 put 存入一 ByteBuffer 中,如下所示:将 hello 存入 ByteBuffer 中

Java代码
ByteBuffer buffer = ByteBuffer.allocate(1024); 
buffer.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o'); 

        此时,position = 5,limit = capacity = 1024。现在我们要从正确的位置从 buffer 读数据,我们可以把 position 置为 0,那么字符串的结束位置在哪呢?这里上界该出场了。如果把上界设置成当前 position 的位置,即 5,那么 limit 就是结束的位置。上界属性指明了缓冲区有效内容的末端。人工实现翻转:


buffer.limit(buffer.position()).position(0);   // 与buffer.flip()等同

        但这种从填充到释放状态的缓冲区翻转是API设计者预先设计好的,他们为我们提供了一个非常便利的函数:buffer.flip()。另外,rewind() 函数与 flip() 相似,但不影响上界属性,它只是将位置值设回 0。在进行buffer读操作的时候,一般都会使用buffer.flip()函数。  




for (int i = 0; buffer.hasRemaining(); i++) { 
    myByteArray[i] = buffer.get(); 

        很明显,上面的代码,每次都要判断元素是否到达上界。我们可以做:改变后的释放过程

int count = buffer.hasRemaining(); 
for (int i = 0; i < count; i++) { 
    myByteArray[i] = buffer.get(); 

        第二段代码看起来很高效,但请注意,缓冲区并不是多线程安全的。如果你想以多线程同时存取特定的缓冲区,你需要在存取缓冲区之前进行同步。因此,使用第二段代码的前提是,你对缓冲区有专门的控制。 
◇ buffer.clear() 
        clear() 函数将缓冲区重置为空状态。它并不改变缓冲区中的任何数据元素,而是仅仅将 limit 设为容量的值,并把 position 设回 0。 




 hasRemaining() 
会告诉你,是否已经达到缓冲区的上界,即limit-position=0,以下是一种将数据元素从缓冲区释放到一个数组的方法:
for(int i = 0; buffer.hasRemaining();i++{
byteArray[i] = buffer.get();

}

缓冲区的比较
两个被认为是相同缓冲区的条件是从position位置开始到limit位置结束,这段字节之内的数据相同,则说明两个缓冲区相同,比较方法为buffer.compareTo(buffer)


相关连接:http://blog.csdn.net/u012345283/article/details/38357851
 http://www.cnblogs.com/lxzh/archive/2013/05/10/3071680.html
原创粉丝点击