知识大全 非阻塞I/O的缓冲区(Buffer)
Posted 知
篇首语:不读书的人,思想就会停止。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 非阻塞I/O的缓冲区(Buffer)相关的知识,希望对你有一定的参考价值。
Java网络编程从入门到精通(33):非阻塞I/O的缓冲区(Buffer) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
如果将同步I/O方式下的数据传输比做数据传输的零星方式(这里的零星是指在数据传输的过程中是以零星的字节方式进行的) 那么就可以将非阻塞I/O方式下的数据传输比做数据传输的集装箱方式(在字节和低层数据传输之间 多了一层缓冲区 因此 可以将缓冲区看做是装载字节的集装箱) 大家可以想象 如果我们要运送比较少的货物 用集装箱好象有点不太合算 而如果要运送上百吨的货物 用集装箱来运送的成本会更低 在数据传输过程中也是一样 如果数据量很小时 使用同步I/O方式会更适合 如果数据量很大时(一般以G为单位) 使用非阻塞I/O方式的效率会更高 因此 从理论上说 数据量越大 使用非阻塞I/O方式的单位成本就会越低 产生这种结果的原因和缓冲区的一些特性有着直接的关系 在本节中 将对缓冲区的一些主要特性进行讲解 使读者可以充分理解缓冲区的概念 并能通过缓冲区来提高程序的执行效率
创建缓冲区
Java提供了七个基本的缓冲区 分别由七个类来管理 它们都可以在java nio包中找到 这七个类如下所示
ByteBuffer
ShortBuffer
IntBuffer
CharBuffer
FloatBuffer
DoubleBuffer
LongBuffer
这七个类中的方法类似 只是它们的返回值或参数和相应的简单类型相对应 如ByteBuffer类的get方法返回了byte类型的数据 而put方法需要一个byte类型的参数 在CharBuffer类中的get和put方法返回和传递的数据类型就是char 这七个类都没有public构造方法 因此 它们不能通过new来创建相应的对象实例 这些类都可以通过两种方式来创建相应的对象实例
通过静态方法allocate来创建缓冲区
这七类都有一个静态的allocate方法 通过这个方法可以创建有最大容量限制的缓冲区对象 allocate的定义如下
ByteBuffer类中的allocate方法
public static ByteBuffer allocate(int capacity)
IntBuffer类中的allocate方法
public static IntBuffer allocate(int capacity)
其他五个缓冲区类中的allocate 方法定义和上面的定义类似 只是返回值的类型是相应的缓冲区类
allocate方法有一个参数capacity 用来指定缓冲区容量的最大值 capacity的不能小于 否则会抛出一个IllegalArgumentException异常 使用allocate来创建缓冲区 并不是一下子就分配给缓冲区capacity大小的空间 而是根据缓冲区中存储数据的情况来动态分配缓冲区的大小(实际上 在低层Java采用了数据结构中的堆来管理缓冲区的大小) 因此 这个capacity可以是一个很大的值 如 * ( M) allocate的使用方法如下
ByteBuffer byteBuffer = ByteBuffer allocate( );IntBuffer intBuffer = IntBuffer allocate( );
在使用allocate创建缓冲区时应用注意 capacity的含义随着缓冲区的不同而不同 如创建字节缓冲区时 capacity指的是字节数 而在创建整型(int)缓冲区时 capacity指的是int型值的数目 如果转换成字数 capacity的值应该乘 如上面代码中的intBuffer缓冲区最大可容纳的字节数是 * = 个
通过静态方法wrap来创建缓冲区
使用allocate方法可以创建一个空的缓冲区 而wrap方法可以利用已经存在的数据来创建缓冲区 wrap方法可以将数组直接转换成相应类型的缓冲区 wrap方法有两种重载形式 它们的定义如下
ByteBuffer类中的wrap方法
public static ByteBuffer wrap(byte[] array)public static ByteBuffer wrap(byte[] array int offset int length)
IntBuffer类中的wrap方法
public static IntBuffer wrap(byte[] array)public static IntBuffer wrap(byte[] array int offset int length)
其他五个缓冲区类中的wrap 方法定义和上面的定义类似 只是返回值的类型是相应的缓冲区类
在wrap方法中的array参数是要转换的数组(如果是其他的缓冲区类 数组的类型就是相应的简单类型 如IntBuffer类中的wrap方法的array就是int[]类型) offset是要转换的子数组的偏移量 也就是子数组在array中的开始索引 length是要转换的子数组的长度 利用后两个参数可以将array数组中的一部分转换成缓冲区对象 它们的使用方法如下
byte[] myByte = new byte[] ;int[] myInt = new int[] ;ByteBuffer byteBuffer = ByteBuffer wrap(myByte);IntBuffer intBuffer = IntBuffer wrap(myInt );
可以通过缓冲区类的capacity方法来得到缓冲区的大小 capacity方法的定义如下
public final int capacity()
如果使用allocate方法来创建缓冲区 capacity方法的返回值就是capacity参数的值 而使用wrap方法来创建缓冲区 capacity方法的返回值是array数组的长度 但要注意 使用wrap来转换array的字数组时 capacity的长度仍然是原数组的长度 如上面代码中的intBuffer缓冲区的capacity值是 而不是
除了可以将数组转换成缓冲区外 也可以通过缓冲区类的array方法将缓冲区转换成相应类型的数组 IntBuffer类的array方法的定义方法如下(其他缓冲区类的array的定义类似)
public final int[] array()
下面的代码演示了如何使用array方法将缓冲区转换成相应类型的数组
int[] myInt = new int[] ;IntBuffer intBuffer = IntBuffer wrap(myInt );for (int v : intBuffer array()) System out print(v + );
在执行上面代码后 我们发现输出的结果是 而不是 这说明在将子数组转换成缓冲区的过程中实际上是将整个数组转换成了缓冲区 这就是用wrap包装子数组后 capacity的值仍然是原数组长度的真正原因 在使用array方法时应注意 在以下两种缓冲区中不能使用array方法
只读的缓冲区如果使用只读缓冲区的array方法 将会抛出一个ReadOnlyBufferException异常
使用allocateDirect方法创建的缓冲区
如果调用这种缓冲区中的array方法 将会抛出一个UnsupportedOperationException异常
可以通过缓冲区类的hasArray方法来判断这个缓冲区是否可以使用array方法 如果返回true 则说明这个缓冲区可以使用array方法 否则 使用array方法将会抛出上述的两种异常之一
注意 使用array方法返回的数组并不是缓冲区数据的副本 被返回的数组实际上就是缓冲区中的数据 也就是说 array方法只返回了缓冲区数据的引用 当数组中的数据被修改后 缓冲区中的数据也会被修改 返之也是如此 关于这方面内容将在下一节 读写缓冲区中的数据 中详细讲解
在上述的七个缓冲区类中 ByteBuffer类和CharBuffer类各自还有另外一种方法来创建缓冲区对象
● ByteBuffer类
可以通过ByteBuffer类的allocateDirect方法来创建ByteBuffer对象 allocateDirect方法的定义如下
public static ByteBuffer allocateDirect(int capacity)
使用allocateDirect方法可以一次性分配capacity大小的连续字节空间 通过allocateDirect方法来创建具有连续空间的ByteBuffer对象虽然可以在一定程度上提高效率 但这种方式并不是平台独立的 也就是说 在一些操作系统平台上使用allocateDirect方法来创建ByteBuffer对象会使效率大幅度提高 而在另一些操作系统平台上 性能会表现得非常差 而且allocateDirect方法需要较长的时间来分配内存空间 在释放空间时也较慢 因此 在使用allocateDirect方法时应谨慎
通过isDirect方法可以判断缓冲区对象(其他的缓冲区类也有isDirect方法 因为 ByteBuffer对象可以转换成其他的缓冲区对象 这部分内容将在后面讲解)是用哪种方式创建的 如果isDirect方法返回true 则这个缓冲区对象是用allocateDirect方法创建的 否则 就是用其他方法创建的缓冲区对象
● CharBuffer类
我们可以发现 上述的七种缓冲区中并没有字符串缓冲区 而字符串在程序中却是最常用的一种数据类型 不过不要担心 虽然java nio包中并未提供字符串缓冲区 但却可以将字符串转换成字符缓冲区(就是CharBuffer对象) 在CharBuffer类中的wrap方法除了上述的两种重载形式外 又多了两种重载形式 它们的定义如下
public static CharBuffer wrap(CharSequence csq)public static CharBuffer wrap(CharSequence csq int start int end)
其中csq参数表示要转换的字符串 但我们注意到csq的类型并不是String 而是CharSequence CharSequence类Java中四个可以表示字符串的类的父类 这四个类是String StringBuffer StringBuilder和CharBuffer(大家要注意 StringBuffer和本节讲的缓冲区类一点关系都没有 这个类在java lang包中) 也就是说 CharBuffer类的wrap方法可以将这四个类的对象转换成CharBuffer对象
另外两个参数start和end分别是子字符串的开始索引和结束索引的下一个位置 如将字符串 中的 转换成CharBuffer对象的语句如下
CharBuffer cb = CharBuffer wrap( );
下面的代码演示了如何使用wrap方法将不同形式的字符串转换成CharBuffer对象
cha138/Article/program/Java/hx/201311/26505相关参考
Java网络编程从入门到精通(32):一个非阻塞I/O的例子 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看
Merlin的魔力:Merlin的新I/O缓冲区的输入和输出 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看
检测解决SQLServer延迟阻塞I/O问题 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 摘要
Java程序性能优化-缓冲(Buffer)(1) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
知识大全 Java程序性能优化-缓冲(Buffer)(2)[2]
Java程序性能优化-缓冲(Buffer)(2)[2] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧
知识大全 Java程序性能优化-缓冲(Buffer)(2)[1]
Java程序性能优化-缓冲(Buffer)(2)[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧
Java中的缓冲区 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 如果将同步I/O方式下的数据传
首先了解下所谓的javanio是个什么东西! 传统的并发型服务器设计是利用阻塞型网络I/O以多线程的模式来实现的然而由 于系统常常在进行网络读写时处于阻塞状态会大大影响系统的性能自Java开始
测量磁盘I/O 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!我怎样分离OracleI/O来使得性能
分析JavaI/O的工作机制 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 网络I/O优化 网