Java NIO:NIO概述
以下是本文的目录大纲:
一.nio中的几个基础概念
二.channel
三.buffer
四.selector
若有不正之处,请多多谅解并欢迎批评指正。
请尊重作者劳动成果,转载请标明原文链接:
http://www.cnblogs.com/dolphin0520/p/3919162.html
一.nio中的几个基础概念(转载 http://www.cnblogs.com/dolphin0520/p/3919162.html)
在nio中有几个比较关键的概念:channel(通道),buffer(缓冲区),selector(选择器)。
首先从channel说起吧,通道,顾名思义,就是通向什么的道路,为某个提供了渠道。在传统io中,我们要读取一个文件中的内容,通常是像下面这样读取的:
1 public class test { 2 public static void main(string[] args) throws ioexception { 3 file file = new file("data.txt"); 4 inputstream inputstream = new fileinputstream(file); 5 byte[] bytes = new byte[1024]; 6 inputstream.read(bytes); 7 inputstream.close(); 8 } 9 }
这里的inputstream实际上就是为读取文件提供一个通道的。
因此可以将nio 中的channel同传统io中的stream来类比,但是要注意,传统io中,stream是单向的,比如inputstream只能进行读取操作,outputstream只能进行写操作。而channel是双向的,既可用来进行读操作,又可用来进行写操作。
buffer(缓冲区),是nio中非常重要的一个东西,在nio中所有数据的读和写都离不开buffer。比如上面的一段代码中,读取的数据时放在byte数组当中,而在nio中,读取的数据只能放在buffer中。同样地,写入数据也是先写入到buffer中。
下面介绍一下nio中最核心的一个东西:selector。可以说它是nio中最关键的一个部分,selector的作用就是用来轮询每个注册的channel,一旦发现channel有注册的事件发生,便获取事件然后进行处理。
比如看下面的这个例子:
用单线程处理一个selector,然后通过selector.select()方法来获取到达事件,在获取了到达事件之后,就可以逐个地对这些事件进行响应处理。
二.channel
在前面已经提到,channel和传统io中的stream很相似。虽然很相似,但是有很大的区别,主要区别为:通道是双向的,通过一个channel既可以进行读,也可以进行写;而stream只能进行单向操作,通过一个stream只能进行读或者写;
以下是常用的几种通道:
- filechannel
- socketchanel
- serversocketchannel
- datagramchannel
通过使用filechannel可以从文件读或者向文件写入数据;通过socketchannel,以tcp来向网络连接的两端读写数据;通过serversocketchanel能够监听客户端发起的tcp连接,并为每个tcp连接创建一个新的socketchannel来进行数据读写;通过datagramchannel,以udp协议来向网络连接的两端读写数据。
下面给出通过filechannel来向文件中写入数据的一个例子:
public class test { public static void main(string[] args) throws ioexception { file file = new file("data.txt"); fileoutputstream outputstream = new fileoutputstream(file); filechannel channel = outputstream.getchannel(); bytebuffer buffer = bytebuffer.allocate(1024); string string = "java nio"; buffer.put(string.getbytes()); buffer.flip(); //此处必须要调用buffer的flip方法 channel.write(buffer); channel.close(); outputstream.close(); } }
通过上面的程序会向工程目录下的data.txt文件写入字符串"java nio",注意在调用channel的write方法之前必须调用buffer的flip方法,否则无法正确写入内容
三.buffer
buffer,故名思意,缓冲区,实际上是一个容器,是一个连续数组。channel提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由buffer。具体看下面这张图就理解了:
上面的图描述了从一个客户端向服务端发送数据,然后服务端接收数据的过程。客户端发送数据时,必须先将数据存入buffer中,然后将buffer中的内容写入通道。服务端这边接收数据必须通过channel将数据读入到buffer中,然后再从buffer中取出数据来处理。
在nio中,buffer是一个顶层父类,它是一个抽象类,常用的buffer的子类有:
- bytebuffer
- intbuffer
- charbuffer
- longbuffer
- doublebuffer
- floatbuffer
- shortbuffer
如果是对于文件读写,上面几种buffer都可能会用到。但是对于网络读写来说,用的最多的是bytebuffer。
四.selector
selector类是nio的核心类,selector能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取事件然后针对每个事件进行相应的响应处理。这样一来,只是用一个单线程就可以管理多个通道,也就是管理多个连接。这样使得只有在连接真正有读写事件发生时,才会调用函数来进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程,并且避免了多线程之间的上下文切换导致的开销。
与selector有关的一个关键类是selectionkey,一个selectionkey表示一个到达的事件,这2个类构成了服务端处理业务的关键逻辑。
参考资料:
作者:matrix海子
出处:
本博客中未标明转载的文章归作者matrix海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。