Java NIO
Java NIO 由以下几个核心部分组成:
· Channels
· Buffers
· Selectors
Channel 和 Buffer
Channel 有点象流。 数据可以从Channel读到Buffer中(channel.read(buf)),也可以从Buffer 写到Channel(channel.write(buf))中。这里有个图示:
Channel和Buffer有好几种类型。
Channel的实现类:
· FileChannel-------文件IO
· DatagramChanne-------UDP网络IOl
· SocketChannel-------TCP客户端网络IO
· ServerSocketChannel-------TCP服务器端网络IO
Buffer的实现类:
· ByteBuffer
· CharBuffer
· DoubleBuffer
· FloatBuffer
· IntBuffer
· LongBuffer
· ShortBuffer
这些Buffer覆盖了你能通过IO发送的基本数据类型:byte, short, int,long, float, double 和 char。
Selector
Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。
单线程中使用一个Selector处理3个Channel的图示:
Selector的使用:
1、创建一个管道
2、打开一个selector
3、将管道注册到selector中,并指出它所关注的事件
4、selector.select();阻塞的方式获取就绪状态的管道
5、selector.selectedKey();获得就绪状态的管道的集合
6、通过迭代器,遍历这个集合。
Java NIO vs. IO
Java NIO和IO的主要区别
IO | NIO |
Stream oriented | Buffer oriented |
Blocking IO | Non blocking IO |
| Selectors |
1. 面向流与面向缓冲
Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。
Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。同时,它不能前后移动流中的数据。
Java NIO面向缓存,数据放到缓冲区中,需要时可在缓冲区中前后移动。增加了灵活性。
2. 阻塞与非阻塞IO
Java IO的各种流是阻塞的,调用read() 或 write()时,线程被阻塞,直到数据被读取,或数据完全写入。
Java NIO采用非阻塞模式,使一个线程从某通道发送请求读取数据,如果目前没有数据可用时,就什么都不会获取。而不是让线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写同上。
3. 选择器(Selectors)
Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
NIO和IO如何影响应用程序的设计
数据处理
在IO设计中,我们从InputStream或 Reader逐字节读取数据。
代码
1. Name: Anna
2. Age: 25
3. Email: anna@mailserver.com
4. Phone: 1234567890
该文本行的流可以这样处理:
Java代码
1. InputStream input = … ; // get the InputStream from the client socket
2. BufferedReader reader = new BufferedReader(new InputStreamReader(input));
3.
4. String nameLine = reader.readLine();
5. String ageLine = reader.readLine();
6. String emailLine = reader.readLine();
7. String phoneLine = reader.readLine();
从一个阻塞的流中读数据
NIO的实现会有所不同,下面是一个简单的例子:
从一个通道里读数据,直到所有的数据都读到缓冲区里
通道(Channel)
· 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
· 通道可以异步地读写。
· 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。(管道与buffer打交道,线程与buffer打交道)
Channel的实现
这些是Java NIO中最重要的通道的实现:
· FileChannel:从文件中读写数据。
· DatagramChannel:能通过UDP读写网络中的数据。
· SocketChannel:能通过TCP读写网络中的数据。
· ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
基本的 Channel 示例
下面是一个使用FileChannel读取数据到Buffer中的示例:
Java代码
1. RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
2. //获取的一个 文件的管道
3. FileChannel inChannel = aFile.getChannel();
4. //开辟个缓冲区
5. ByteBuffer buf = ByteBuffer.allocate(48);
6. //将文件内容通过管道读到缓存中
7. int bytesRead = inChannel.read(buf);
8. while (bytesRead != -1) {
9. System.out.println("Read " + bytesRead);
10. buf.flip(); //切换缓存读写模式
11.
12. while(buf.hasRemaining()){
13. System.out.print((char) buf.get());
14. }
15.
16. buf.clear();
17. bytesRead = inChannel.read(buf);
18. }
19. aFile.close();