从JDK1.4开始,JDK提供了一套专门的类库支持非阻塞I/O,可以在java.nio包及其子包中找到相关的类和接口。由于这套API是新提供的I/O API,因此也叫New I/O,这就是JAVA NIO的由来。非阻塞IO API由3个主要部分组成:缓冲区(Buffers)、通道(Channels)和Selector
NIO服务端创建过程
- 打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父管道 - 1 - ServerSocketChannel acceptorSrv = ServerSocketChannel.open(); 
- 绑定监听端口,设置连接为非阻塞模式 - 1 
 2
 3- acceptorSrv.socket().bind(new InetSocketAddress(InetAddress.getByName("IP"), port)); 
 acceptorSrv.configureBlocking(false);
- 创建Reactor线程,创建多路复用器并启动线程 - 1 
 2
 3- Selector selector = Selector.open(); 
 new Thread(new ReactorTask()).start();
- 将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件 - 1 - SelectionKey key = acceptorSvr.register(selector, SelectionKey.OP_ACCEPT, ioHandler); 
- 多路复用器在线程run方法的无限循环体内轮询准备就绪的Key - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- int num = selector.select(); 
 Set selectedKeys = selector.selectKeys();
 Iterator it = selectedKeys.iterator();
 while(it.hasNext()) {
 SelectionKey key = (SelectionKey) in.next();
 //...deal with I/O event...
 }
- 多路复用器监听到有新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路 - 1 - SocketChannel channel = svrChannel.accept(); 
- 设置客户端链路的TCP参数 - 1 
 2
 3- channel.configureBlocking(false); 
 channel.socket().setReuseAddress(true);
- 将新接入的客户端连接注册到Reactor线程的多路复用器上,监听读操作 - 1 - SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ, ioHandler); 
- 异步读取客户端请求消息到缓冲区 - 1 - int readNum = channel.read(receiveeBuffer); 
- 对ByteBuffer进行编解码,如果有半包消息指针Reset,继续读取后续的报文,将解码成功的消息封装成Task,投递到业务线程池中,进行业务逻辑操作 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 Object message = null;
 while(buffer.hasRemain()) {
 byteBuffer.remark();
 message = decode(byteBuffer);
 if(message == null) {
 byteBuffer.reset();
 break;
 }
 messageLisk.add(message);
 }
- 将POJO对象encode成ByteBuffer,调用SocketChannel的异步write接口,将消息异步发送给客服端 - 1 - socketChannel.write(buffer); 
