linugb118--java space

Java

Java NIO---buffer部分

Java NIO---buffer部分

最近想建一个网络传输的平台,查看到了Jboss 的Netty,而他们核心的传输是用了JDK 1.4以后的
NIO特性,因此借机会学习一下NIO
NIO主要有下面几大部分

Buffer:Io的操作少不了缓存,通过Buffer能大大提高传输的效率,同样NIO中也有Buffer的这部分
Buffer针对数据类型有相应的子类,他们都是继承Buffer class
比如CharBuffer,IntBuffer等等
需要说明的子类MappedByteBuffer 通过命名可以看出这个MappedByteBuffer有mapped+byte+Buffer组成
据我理解 这么mapped 是指memory-mapped
这里解释一下memory-mapped, 以为我们说的buffer 可能就是指物理上的内存,包括jdk 以前的io
一般情况下,buffer指物理上的内存没什么问题,可以物理内存毕竟比较有限,当需要很大buffer存放数据的时候
物理内存就不够,那么就引出一个虚拟内存的概念,就像现在的os 一样,也有虚拟内存的概念,虚拟内存本质上
是存在硬盘上的,只是物理内存存放的不是具体的数据而是虚拟内存上的地址,而具体的数据则是在虚拟内存上,这样
物理内存只是存放很多地址,这样就大大增加了buffer的size。当然如果你buffer的数据很小,也可以知道放入物理内存
因此我认为 这个memory-mapped 是指的用虚拟内存的哪种缓存模式

A.Buffer的 attribute
1.Capacity:buffer的大小,一个buffer按照某个Capacity创建后就不能修改
2.Limit:用了多少buffer
3.Position:指针,获取下一个元素的位置,操作get(),put(),这个position会自动更新(和iterator相似)
4.Mark:被标记的指针位置 通过mark()操作可以使mark = position 通过reset() 可以使position = mark

上面这几个属性应该符合下面条件
0 <= mark <= position <= limit <= capacity


B. fill:插入数据
用put() 方法可以插入一段数据 但是这个时候postion 在插入这段数据的尾部

C. flip:弹出数据
因为上面写入数据后,指针在尾部不是从0开始,那么我们需要
buffer.limit(buffer.position( )).position(0);
将limit 设置为当前的postion,limit 可以告诉方法这段数据什么时候结束,而具体可以调用方法
hasRemaining( ) 来判断是否数据结束。

同时将当前指针设置为0
NIO 提供了方法buffer.flip()完成上面的动作

另外方法rewind( )和flip相似 只是区别在于flip要修改limit,而rewind不修改limit
rewind 用处可以在已经flip后,还能重读这段数据

Buffer不是线程安全的,如果你想要多线程同时访问,那么需要用synchronization

D. Mark:让buffer记住某个指针,已备后面之用。
调用mark()就能将当前指针mark住
而调用reset()就能将当前指针回到mark了的指针位置,如果mark未定义,那么调用reset就会报InvalidMarkException
此外rewind( ), clear( ), and flip( )这些操作将会抛弃mark,这样clear()和reset()区别
clear表示清空buffer 而reset表示能将当前指针回到mark了的指针位置

E:Comparing:buffer 也是java的object sub class,所有buffer也能对象进行比较
public abstract class ByteBuffer
extends Buffer implements Comparable
{
// This is a partial API listing
public boolean equals (Object ob)
public int compareTo (Object ob)
}

两个buffer 认为相等,需要具备下面条件
1.buffer 类型相同
2.buffer里面保留的元素数量相同,buffer capacities不需要相同,这里需要注意保留的元素是指有效的元素,不是指buffer里面有的元素。
其实就从position到limit这段的元素,当然当前的postion和limit值都可以不相同,但这段数据要相同
3.remaining data 的数据顺序要相同,可以通过get()来循环获取出来后判断每个element都相同

如果同时符合上面三个条件,那么就表示buffer object 相等

F:Bulk Moves
如何在buffer中大块的数据移动,对性能起到关键作用
他的做法是get的时候,将一块数据取出放入数组里面,这样比起循环get()一个byte要效率高多了,那么对于块状数据总是有个指定的长度
这个长度就是指定数组的长度
public CharBuffer get (char [] dst, int offset, int length)
这里就是length。
如果只有参数为数组buffer.get (myArray);
那么其实也是指定了长度,只是长度为数组的长度,上面的语句等同于
buffer.get (myArray, 0, myArray.length);
针对上面,有可能buffer的data 小于myArray.length,这个时候如果取buffer 那么会报错
所以需要下面的写法
 char [] bigArray = new char [1000];
 // Get count of chars remaining in the buffer
 int length = buffer.remaining( );
 // Buffer is known to contain < 1,000 chars
 buffer.get (bigArrray, 0, length);
 // Do something useful with the data
 processData (bigArray, length);
 这是buffer<length
 如果buffer>length 那需要loop:
 char [] smallArray = new char [10];
 while (buffer.hasRemaining( )) {
 int length = Math.min (buffer.remaining( ), smallArray.length);
 buffer.get (smallArray, 0, length);
 processData (smallArray, length);
 }

同样操作put是将array中的数据放入buffer,他同样有上面length的问题,需要用remaining来判断

G:创建Buffer: buffer class 不能直接new创建,他们都是abstract class,但是他们都有static factory,通过factory可以创建instances
比如
public abstract class CharBuffer
extends Buffer implements CharSequence, Comparable
{
// This is a partial API listing
public static CharBuffer allocate (int capacity)
public static CharBuffer wrap (char [] array)
public static CharBuffer wrap (char [] array, int offset,
int length)
public final boolean hasArray( )
public final char [] array( )
public final int arrayOffset( )
}

可以通过allocation或者wrapping来创建buffer
Alloction:允许分配私有buffer
CharBuffer charBuffer = CharBuffer.allocate (100);
wrapping:不允许分配私有buffer,显性提供存储
char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);

而myArray  叫做buffer的backing array
通过hasArray( ) 判断buffer是否存在backing array
如果为true,可通过array()得到array的引用

H:Duplicating Buffers  复制buffer
Duplicat() 创建一个和原来一样的新的buffer,他们都有各自的postion,limit,mark, 但是共享同样的数据,也就是说任何一个buffer被修改了
他们看到的数据也就修改了。创建的新buffer继承了老buffer的属性,比如如果老buffer为readonly,那么新的也是readonly
asReadOnlyBuffer( ) 和Duplicat()相似,只是区别asReadOnlyBuffer( ) 创建的buffer总是readonly
slice() 和Duplicat()也相似,不同之处在于slice() 将修改buffer的capacity=(limit - position),同时新buffer以老buffer的当前postion作为开始
指针。

I:Byte Buffers 可以获取不同类型的buffer,另外byte本身也能排序

J:Direct Buffers: 对于操作系统来说,内存存储的数据不一定是连续的。而Direct buffer直接用于和io设备进行交互,对于io设备操作的buffer只能是
direct buffer,如果是nondirect ByteBuffer需要写入设备,那么他首先是创建一个临时的direct byteBuffer,然后将内容考入这个临时direct buffer,
接着进行底层的io操作,完成io操作后,临时buffer将被垃圾回收。
ByteBuffer.allocateDirect()创建direct buffer,isDirect( )则判断buffer是否是direct buffer

K:View Buffers  当一堆数据被收到后需要先查看他,然后才能确定是send还是怎么处理,这个时候就要引入View buffer
View Buffer拥有自己的属性,比如postion,limit,mark,但是他是和初始buffer共享数据的,这个和duplicated,sliced相似,但是view Buffer
能将raw bytes 映射为指定的基础类型buffer,这个也是查看的具体内容了,我们也可以认为是byte buffer向其他基础类型buffer的转换

public abstract class ByteBuffer
extends Buffer implements Comparable
{
// This is a partial API listing
public abstract CharBuffer asCharBuffer( );
public abstract ShortBuffer asShortBuffer( );
public abstract IntBuffer asIntBuffer( );
public abstract LongBuffer asLongBuffer( );
public abstract FloatBuffer asFloatBuffer( );
public abstract DoubleBuffer asDoubleBuffer( );
}

 

 

 

 

 

 

 

 

 

 

posted on 2010-09-01 16:01 linugb118 阅读(1717) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 

My Links

Blog Stats

常用链接

留言簿(1)

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜