java nio是从java 1.4版本开始引入的。Java NIO和IO之间最大的区别:IO是面向流的,NIO是面向缓冲区的。nio核心组件:channel buffer selector三大组件

java io适用场景(原文链接:http://tutorials.jenkov.com/java-nio/overview.html):

1、并发量较小;

2、单连接一次发送数据包较大(要求内存足够,此读写线程阻塞);

java nio适用场景:

1、并发量较大;

2、单连接一次发送数据包不大(数据包较大,读数据处理复杂度高),如QQ聊天;

channel 类似于流,但流是意向的,通道是双向的

    //从文件中读写数据
        FileChannel fc = null;
        //能通过TCP读写网络中的数据
        SocketChannel sc = null;
        //能通过UDP读写网络中的数据
        DatagramChannel dc = null;
        //可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。 
        ServerSocketChannel ssc = null; 

一 通道Channel

Java NIO的通道类似流,但又有些不同: 

    • 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
    • 通道可以异步地读写。
    • 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

Java NIO中最重要的通道的实现: 

    • FileChannel:从文件中读写数据。
    • DatagramChannel:能通过UDP读写网络中的数据。
    • SocketChannel:能通过TCP读写网络中的数据。
    • ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

 

二 组件buffer

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。 

Java NIO 有以下Buffer类型: 

    • ByteBuffer
    • MappedByteBuffer
    • CharBuffer
    • DoubleBuffer
    • FloatBuffer
    • IntBuffer
    • LongBuffer
    • ShortBuffer

 三 组件selector

Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。 通常线程越少开销越小,但当前处理器多为多核处理器,多线程任务应该得到充分利用。

一旦向Selector注册了一或多个通道,就可以调用几个重载的select()方法。这些方法返回你所感兴趣的事件(如连接、接受、读或写)已经准备就绪的那些通道。换句话说,如果你对“读就绪”的通道感兴趣,select()方法会返回读事件已经就绪的那些通道。 

下面是select()方法: 

  • int select()
  • int select(long timeout)
  • int selectNow()

select()阻塞到至少有一个通道在你注册的事件上就绪了。 

select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。 

selectNow()不会阻塞,不管什么通道就绪都立刻返回(译者注:此方法执行非阻塞的选择操作。如果自从前一次选择操作后,没有通道变成可选择的,则此方法直接返回零。)。 

select()方法返回的int值表示有多少通道已经就绪。

selector不会主动向通道发送已就绪事件,需要通过select()方法来获取就绪的通道,根据SelectionKey确定是哪个通道,进行相关的业务处理。

示例代码:

 1 Selector selector = Selector.open();  
 2 channel.configureBlocking(false);  
 3 SelectionKey key = channel.register(selector, SelectionKey.OP_READ);  
 4 while(true) {  
 5   int readyChannels = selector.select();  
 6   if(readyChannels == 0) continue;  
 7   Set selectedKeys = selector.selectedKeys();  
 8   Iterator keyIterator = selectedKeys.iterator();  
 9   while(keyIterator.hasNext()) {  
10     SelectionKey key = keyIterator.next();  
11     if(key.isAcceptable()) {  
12         // a connection was accepted by a ServerSocketChannel.  
13     } else if (key.isConnectable()) {  
14         // a connection was established with a remote server.  
15     } else if (key.isReadable()) {  
16         // a channel is ready for reading  
17     } else if (key.isWritable()) {  
18         // a channel is ready for writing  
19     }  
20     keyIterator.remove();  
21   }  
22 }  

 

这个循环遍历已选择键集中的每个键,并检测各个键所对应的通道的就绪事件。
注意每次迭代末尾的keyIterator.remove()调用。Selector不会自己从已选择键集中移除SelectionKey实例。必须在处理完通道时自己移除。下次该通道变成就绪时,Selector会再次将其放入已选择键集中。

四 管道pipe

Java NIO 管道是2个线程之间的单向数据连接(用于线程间数据传递)。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。

直接上示例代码:

 1 package com.lanhuigu.nio.channel;
 2  
 3 import java.io.IOException;
 4 import java.nio.ByteBuffer;
 5 import java.nio.channels.Pipe;
 6  
 7 public class TestPipe {
 8     public static void main(String[] args) throws IOException {
 9         // 1. 获取管道
10         Pipe pipe = Pipe.open();
11  
12         // 2. 将缓冲区数据写入到管道
13         // 2.1 获取一个通道
14         Pipe.SinkChannel sinkChannel = pipe.sink();
15         // 2.2 定义缓冲区
16         ByteBuffer buffer = ByteBuffer.allocate(48);
17         buffer.put("发送数据".getBytes());
18         buffer.flip(); // 切换数据模式
19         // 2.3 将数据写入到管道
20         sinkChannel.write(buffer);
21  
22         // 3. 从管道读取数据
23         Pipe.SourceChannel sourceChannel = pipe.source();
24         buffer.flip();
25         int len = sourceChannel.read(buffer);
26         System.out.println(new String(buffer.array(),0,len));
27  
28         // 4. 关闭管道
29         sinkChannel.close();
30         sourceChannel.close();
31     }
32 }

View Code

 

版权声明:本文为lwy329原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/lwy329/p/9844554.html