`
962685987962685987
  • 浏览: 5172 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java网络编程从入门到精通(33):非阻塞I/O的缓冲区(Buffer)

阅读更多
如果将同步 I/O方式下的数据传输比做数据传输的零星方式(这里的零星是指在数据传输的过程中是以零星的字节方式进行的),那么就可以将非阻塞 I/O方 式下的数据传输比做数据传输的集装箱方式(在字节和低层数据传输之间,多了一层缓冲区,因此,可以将缓冲区看做是装载字节的集装箱)。大家可以想象,如果 我们要运送比较少的货物,用集装箱好象有点不太合算,而如果要运送上百吨的货物,用集装箱来运送的成本会更低。在数据传输过程中也是一样,如果数据量很小 时,使用同步 I/O方式会更适合,如果数据量很大时(一般以 G为单位),使用非阻塞 I/O方式的效率会更高。因此,从理论上说,数据量越大,使用非阻塞 I/O方式的单位成本就会越低。产生这种结果的原因和缓冲区的一些特性有着直接的关系。在本节中,将对缓冲区的一些主要特性进行讲解,使读者可以充分理解缓冲区的概念,并能通过缓冲区来提高程序的执行效率。
创建缓冲区
Java提供了七个基本的缓冲区,分别由七个类来管理,它们都可以在 java.nio包中找到。这七个类如下所示:
  •   ByteBuffer   
  • ShortBuffer
  • IntBuffer
  • CharBuffer
  • FloatBuffer
  • DoubleBuffer
  • LongBuffer
st1":*{behavior:url(#ieooui) }
这七个类中的方法类似,只是它们的返回值或参数和相应的简单类型相对应,如 ByteBuffer类的 get方法返回了 byte类型的数据,而 put方法需要一个 byte类型的参数。在 CharBuffer类中的 get put方法返回和传递的数据类型就是 char。这七个类都没有 public构造方法,因此,它们不能通过 new来创建相应的对象实例。这些类都可以通过两种方式来创建相应的对象实例。
1.        通过静态方法 allocate来创建缓冲区。
这七类都有一个静态的 allocate方法,通过这个方法可以创建有最大容量限制的缓冲区对象。 allocate的定义如下:
ByteBuffer 类中的 allocate 方法:
public   static  ByteBuffer allocate( int  capacity)
IntBuffer 类中的 allocate 方法:
public   static  IntBuffer allocate( int  capacity)
其他五个缓冲区类中的 allocate 方法定义和上面的定义类似,只是返回值的类型是相应的缓冲区类。
allocate方法有一个参数 capacity,用来指定缓冲区容量的最大值。 capacity的不能小于 0,否则会抛出一个 IllegalArgumentException异常。使用 allocate来创建缓冲区,并不是一下子就分配给缓冲区 capacity大小的空间,而是根据缓冲区中存储数据的情况来动态分配缓冲区的大小(实际上,在低层 Java采用了数据结构中的堆来管理缓冲区的大小),因此,这个 capacity可以是一个很大的值,如 1024*1024 1M)。 allocate的使用方法如下:
ByteBuffer byteBuffer  =  ByteBuffer.allocate( 1024 );
IntBuffer intBuffer 
=  IntBuffer.allocate( 1024 );
    在使用 allocate创建缓冲区时应用注意, capacity的含义随着缓冲区的不同而不同。如创建字节缓冲区时, capacity指的是字节数。而在创建整型 (int)缓冲区时, capacity指的是 int型值的数目,如果转换成字数, capacity的值应该乘 4。如上面代码中的 intBuffer缓冲区最大可容纳的字节数是 1024*4 = 4096个。
2.        通过静态方法 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 [] {  1 2 3  };
int [] myInt  =   new   int [] {  1 2 3 4  };
ByteBuffer byteBuffer 
=  ByteBuffer.wrap(myByte);
IntBuffer intBuffer 
=  IntBuffer.wrap(myInt,  1 2 );
可以通过缓冲区类的 capacity方法来得到缓冲区的大小。 capacity方法的定义如下:
public   final   int  capacity()
如果使用 allocate方法来创建缓冲区, capacity方法的返回值就是 capacity参数的值。而使用 wrap方法来创建缓冲区, capacity方法的返回值是 array数组的长度,但要注意,使用 wrap来转换 array的字数组时, capacity的长度仍然是原数组的长度,如上面代码中的 intBuffer缓冲区的 capacity值是 4,而不是 2
除了可以将数组转换成缓冲区外,也可以通过缓冲区类的 array方法将缓冲区转换成相应类型的数组。 IntBuffer类的 array方法的定义方法如下(其他缓冲区类的 array的定义类似):
public   final   int [] array()
    下面的代码演示了如何使用 array方法将缓冲区转换成相应类型的数组。

int [] myInt  =   new   int [] {  1 2 3 4 5 6  };
IntBuffer intBuffer 
=  IntBuffer.wrap(myInt,  1 3 );
for  ( int  v : intBuffer.array())
    System.out.print(v 
+   "   " );
在执行上面代码后,我们发现输出的结果是 1 2 3 4 5 6,而不是 2 3 4。这说明在将子数组转换成缓冲区的过程中实际上是将整个数组转换成了缓冲区,这就是用 wrap包装子数组后, capacity的值仍然是原数组长度的真正原因。在使用 array方法时应注意,在以下两种缓冲区中不能使用 array方法:
  • 只读的缓冲区
如果使用只读缓冲区的 array方法,将会抛出一个 ReadOnlyBufferException异常。
  • 使用 allocateDirect方法创建的缓冲区
如果调用这种缓冲区中的 array方法,将会抛出一个 UnsupportedOperationException异常。
可以通过缓冲区类的 hasArray方法来判断这个缓冲区是否可以使用 array方法,如果返回 true,则说明这个缓冲区可以使用 array方法,否则,使用 array方法将会抛出上述的两种异常之一。

注意: 使用array方法返回的数组并不是缓冲区数据的副本。被返回的数组实际上就是缓冲区中的数据,也就是说,array方法只返回了缓冲区数据的引用。当数 组中的数据被修改后,缓冲区中的数据也会被修改,返之也是如此。关于这方面内容将在下一节“读写缓冲区中的数据”中详细讲解。

在上述的七个缓冲区类中, ByteBuffer类和 CharBuffer类各自还有另外一种方法来创建缓冲区对象。
l         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方法创建的,否则,就是用其他方法创建的缓冲区对象。
l         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分别是子字符串的开始索引和结束索引的下一个位置,如将字符串 "1234"中的 "23" 转换成 CharBuffer对象的语句如下:
CharBuffer cb  =  CharBuffer.wrap( " 1234 " 1 3 );
    下面的代码演示了如何使用 wrap方法将不同形式的字符串转换成 CharBuffer对象。
StringBuffer stringBuffer  =   new  StringBuffer( " 通过StringBuffer创建CharBuffer对象 " );
StringBuilder stringBuilder 
=   new  StringBuilder( " 通过StringBuilder创建CharBuffer对象 " );
CharBuffer charBuffer1 
=  CharBuffer.wrap( " 通过String创建CharBuffer对象 " );
CharBuffer charBuffer2 
=  CharBuffer.wrap(stringBuffer);
CharBuffer charBuffer3 
=  CharBuffer.wrap(stringBuilder);
CharBuffer charBuffer4 
=  CharBuffer.wrap(charBuffer1,  1 3 );

本文出自 “软件改变整个宇宙 ” 博客,请务必保留此出处http://androidguy.blog.51cto.com/974126/214328

分享到:
评论

相关推荐

    java阻塞i/o与非阻塞i/o控制

    了解并熟练掌握这两种I/O模型,有助于开发者编写出高效、可扩展的Java应用程序,特别是在网络编程和服务器开发中,非阻塞I/O能够带来显著的性能提升。因此,深入学习和实践Java中的阻塞I/O与非阻塞I/O控制是非常必要...

    Java网络编程从入门到精通

    5. **NIO(非阻塞I/O)**:Java NIO(New IO)是自Java 1.4引入的新API,它提供了选择器、通道和缓冲区等机制,可以提高网络编程的效率和性能。 6. **HTTP客户端库**:Java提供了HttpURLConnection来处理HTTP请求,...

    JAVA网络编程从入门到精通

    ### JAVA网络编程从入门到精通知识点详解 #### 一、Internet地址概述 互联网中的每一台设备都需要有一个唯一的标识符——IP地址。当前广泛使用的IPv4地址由四个字节组成,而未来的趋势是采用16个字节的IPv6地址。 ...

    芯片I/O缓冲及ESD电路设计

    在电子设计领域,芯片I/O缓冲及ESD电路设计是至关重要的环节,它们关系到芯片与外界环境的交互效率和稳定性。I/O缓冲电路作为芯片与外部系统通信的桥梁,承担着信号转换、驱动和保护的重要任务。这篇文章将深入探讨I...

    I/O缓冲池演示程序

    4. 请求调度:根据I/O请求的优先级和缓冲区的状态,决定哪个请求应先执行,以及数据应从哪个缓冲区传输。 5. 错误处理:捕获并处理可能出现的I/O错误,确保程序的健壮性。 在实际应用中,I/O缓冲池不仅可以用于磁盘...

    Java I/O, 2nd Edition

    这本书在第二版中对Java I/O进行了更新,涵盖了从Java 5到Java 8的最新发展,包括NIO.2(New I/O 2)框架的介绍。 1. **Java I/O基础**:书中首先介绍了Java I/O的基本概念,如流、缓冲区、字符编码和文件操作。流...

    Java I/O编程 java

    Java I/O 编程是Java开发中的重要组成部分,主要用于处理数据的输入与输出。下面将详细阐述其中的关键概念和方法。 1. 数据流的概念及输入输出方法: 数据流是计算机中进行数据传输的通道,包括从外部设备到程序的...

    Java 新I/O

    Java 新I/O,也称为NIO(New Input/Output),是Java平台中对传统I/O模型的一种改进。在Java 1.4版本中引入的NIO库为开发人员提供了更高效、非阻塞的数据处理方式,特别适用于高并发、低延迟的系统。NIO的核心在于...

    怎么使用I/O编程???

    在Java编程中,I/O(Input/Output)处理是与外部世界交互的关键技术,涉及文件读写、网络通信等场景。I/O的核心思想是通过流(Stream)来传输数据,使得程序能从数据源读取数据或将数据写入目标。 **1.1 I/O简介** I...

    jdk6.0从入门到精通-----chapter5网络编程 新I/O(含源码下载)

    在Java编程领域,JDK(Java Development Kit)是开发和运行Java应用程序的...总的来说,"JDK6.0从入门到精通-----chapter5网络编程 新I/O"是一个极好的学习资源,无论你是初学者还是有经验的开发者,都能从中获益良多。

    Java网络编程.pdf

    ### Java网络编程精要 #### Internet地址概述与分类 ...以上是对Java网络编程中一些核心知识点的概括,涵盖了从IP地址管理、套接字通信到非阻塞I/O模型的各个方面,为深入理解和应用Java网络编程技术奠定了基础。

    魔乐科技:从入门到精通Java全部源码

    4. **输入输出流**:IO流的基本概念,字符流和字节流,缓冲流,以及NIO(非阻塞I/O)的概念。 5. **线程编程**:线程的创建方式,同步机制(synchronized,wait(),notify(),锁),线程池的使用。 6. **反射机制*...

    Java 非阻塞I/O使用方法

    Java 非阻塞I/O使用方法 Java 非阻塞I/O是处理高并发的一种手段,在高并发的情况下,创建和回收线程以及在线程间切换的开销变得不容忽视,此时就可以使用非阻塞I/O技术。这种技术的核心思想是每次选取一个准备好的...

    Java网络编程期末考试复习题库+答案

    在Java中,网络编程主要依赖于Java的Socket编程、ServerSocket、URL类以及NIO(非阻塞I/O)等核心API。这份"Java网络编程期末考试复习题库+答案"为学生提供了全面的复习资源,涵盖了Java网络编程的主要知识点。 1. ...

    Java I/O, NIO and NIO.2

    非阻塞I/O(Non-blocking I/O),简称NIO,是Java 1.4引入的一个重要特性,主要由java.nio包提供。NIO的核心在于通道(Channels)和缓冲区(Buffers)。通道类似于流,但它们支持非阻塞读写,这意味着当数据不可用时...

    buffer应用缓冲区

    同时,为了确保数据的完整性和一致性,需要正确处理缓冲区满或空的情况,例如采用非阻塞I/O或信号驱动I/O。 总的来说,Buffer在应用缓冲区和Socket通信中的应用是提高系统效率、优化数据处理的关键。了解并掌握...

    《Java网络编程实例:Java网络编程实例》

    7. **NIO(非阻塞I/O)**:Java NIO(New I/O)提供了一种更高效的数据处理方式,特别是在处理大量并发连接时。通道(Channels)和缓冲区(Buffers)是NIO的核心概念。 8. **HTTP协议**:作为应用层最常用的协议之...

    深入分析 Java I/O 的工作机制(转载)

    Java I/O(输入/输出)系统是Java编程语言中用于处理数据流的重要组成部分,它允许程序与外部资源如文件、网络、硬件设备等进行交互。深入理解Java I/O的工作机制对于开发高效、可靠的系统至关重要。以下是对Java I/...

    精通java网络编程

    五、NIO(非阻塞I/O) Java的NIO(New I/O)库提供了一种更高效的I/O模型,它支持选择器(Selector)和通道(Channel),可以在单个线程中处理多个连接,减少了线程创建和销毁的开销。Selector可以监控多个Channel,...

    java从入门到精通(第三版)光盘实例

    《Java从入门到精通》(第三版)是一本旨在帮助初学者和有一定基础的程序员深入理解Java编程语言的书籍。光盘实例作为该书的重要补充,提供了丰富的代码示例和实际应用,帮助读者巩固理论知识并提升实战技能。在这些...

Global site tag (gtag.js) - Google Analytics