您的位置:首页 > Web前端

Java的NIO之详解通道Channel和字节缓冲区ByteBuffer

2014-11-23 11:33 597 查看
http://kakajw.iteye.com/blog/1788867

一. 什么是通道

I/O通道(Channel):

一种专门负责执行IO任务的处理机/处理器,具有执行I/O指令的能力,并通过执行通道程序来完成I/O操作,它的作用是建立独立的IO操作,将CPU从繁多的低速IO操作中解脱。

 

详细解释:

1. 当CPU和I/O设备之间增加设备控制器后,已经可以大大减少IO对CPU的依赖,而IO通道的出现是为了建立独立的IO操作,从而进一步减轻CPU的负担。

2. 通道管理设备控制器,而这些控制器控制着IO设备(如磁盘驱动器、终端、LAN端口),同时通道具有执行I/O指令的能力,与CPU交互。

3. 当需要执行IO操作时,CPU只需向通道发一条IO指令,通道执行通道处理程序,通过和设备控制器交互,开始IO操作;当IO操作完成后,通道向CPU发送信号;CPU在发送IO指令至接收到IO完成的信号期间可以运行和该IO操作无关的任务,使得CPU可以专门负责处理高速任务,低速的IO任务交给通道完成,整体任务处理效率得到提高。

 

4. 对于Java的nio,通道的意义在于对异步IO的支持,是nio的关键对象。

 

 

二. 什么是ByteBuffer

ByteBuffer,也称为字节缓冲区,也是Java nio的关键对象。

1. 通道负责处理IO操作,相对于应用程序,是IO数据的源头或目的地,而ByteBuffer是应用程序和通道之间进行IO数据传输的中转地/缓冲区,且是nio中唯一直接和通道交互的缓冲区。

2. ByteBuffer本质是内存的一块区域,可存放原始字节。

相关内容(Linux的基础IO模型):

   a. Linux的内核将所有外部设备都可以看做文件来操作。应用程序与外部设备的操作都可以看成对文件进行操作。应用程序对文件的读写,都通过调用内核提供的系统调用;内核给我们返回一个file descriptor(简称:fd,文件描述符);通过 ls -l  /proc/${pid}/fd/ 可以看到进程${pid}占用的所有描述符,或者lsof -p ${pid}; 而对一个socket的读写也会有相应的描述符,称为socketfd(socket描述符);描述符就是一个数字,指向内核中一个结构体(文件路径,数据区,等一些属性)
; 那么应用程序对文件的读写就通过对描述符的读写完成。   

   b. 系统调用是如何完成一个I/O操作的呢? linux将内存分为内核区,用户区;应用程序通过调用系统调用和内核交互,使用Linux所有的硬件资源;如通过系统调用read发起一个读操作,此时内核创建一个文件描述符,并通过驱动程序向硬件发送读指令,并将读的的数据放在这个描述符对应结构体的缓存区。但这个结构体是在内核内存区的。需要将这个数据读到用户区的内存,这样完成了一次读操作,如果应用程序是通过java nio方式读取,那么该前述用户区的内存就是ByteBuffer;write操作类似。

    c. 但是大家都知道I/O设备相比cpu的速度是极慢的。linux提供的read系统调用,也是一个阻塞函数。这样我们的应用进程在发起read系统调用时,就必须阻塞,就进程被挂起而等待文件描述符的读就绪。     

       什么是文件描述符读就绪,什么是写就绪?

       读就绪:就是这个文件描述符的接收缓冲区中的数据字节数大于等于套接字接收缓冲区(可认为是byteBuffer)低水位标记的当前大小;

       写就绪:该描述符发送缓冲区的可用空间字节数大于等于描述符发送缓冲区(可认为是byteBuffer)低水位标记的当前大小。如果是socket fd,说明上一个数据已经发送完成)。

       接收低水位标记和发送低水位标记:由应用程序指定,比如应用程序指定接收低水位为64个字节。那么接收缓冲区有64个字节,才算fd读就绪;

 

  d.小结: 对于Linux的基础IO模型,byteBuffer是用户区的存放数据的缓冲区,与内核区的结构体缓存区对应,是IO数据在内核(通道属于内核)和应用程序之间传送的中转站;而上述的关于IO操作的内核系统调用相当于通道处理程序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: