您的位置:

NIO Selector

一、NIO Selector的定义和作用

Java NIO(New IO)是从Java 1.4版本开始引入的,用于替代原来的Java IO API,NIO提供了一种面向缓冲区的、基于通道的I/O操作方式。NIO中的Selector其实是一个选择器,用于处理多个通道的选择性IO操作。以前,一个线程只能处理一个连接,而Selector提供了一种可以通过一个线程处理多个连接的方式。

在使用NIO编程时,Selector负责监控被注册进它里面的Channel,当Channel中有可以进行IO操作的状态时,Selector将会得到通知,进行相应的处理,而不需要线程一直轮询。因此,NIO Selector解决了Java BIO的瓶颈问题,保证了处理高并发连接时系统性能和可靠性的平衡。

二、NIO Selector的基本使用方法

下面给出一个简单的例子来说明如何使用NIO Selector实现服务端与客户端的简单通信:

    Selector selector = Selector.open();
    ServerSocketChannel serverSocket = ServerSocketChannel.open();
    serverSocket.bind(new InetSocketAddress(8080));
    serverSocket.configureBlocking(false);
    SelectionKey selectionKey = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
    while (true) {
        selector.select();
        Set<SelectionKey> selectionKeys = selector.selectedKeys();
        Iterator<SelectionKey> iterator = selectionKeys.iterator();
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            if (key.isAcceptable()) {
                ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                SocketChannel socketChannel = serverSocketChannel.accept();
                socketChannel.configureBlocking(false);
                socketChannel.register(selector, SelectionKey.OP_READ);
                System.out.println("建立链接");
            } else if (key.isReadable()) {
                SocketChannel socketChannel = (SocketChannel) key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                socketChannel.read(buffer);
                String receive = new String(buffer.array());
                System.out.println("接收到客户端的信息:" + receive);
            }
            iterator.remove();
        }
    }

上述代码中,我们首先创建一个Selector实例并打开一个ServerSocketChannel,然后将ServerSocketChannel注册到Selector上,并且声明该Selector对客户端连接请求(OP_ACCEPT)感兴趣。

最后通过不断地轮询select()方法,来检查是否有连接已经准备好进行I/O操作。在select()方法返回之后,我们通过迭代器获取可操作的SelectionKey集合,然后进行相应操作,例如建立连接或者从通道中读取数据。

三、NIO Selector的优缺点

NIO Selector有以下几个优点:

1、单线程可以处理多个连接,降低了系统开销,提高了系统的伸缩性;

2、为非阻塞I/O提供了一个优良的基础,Selector监听多个Channel的I/O事件的能力使得单个线程可以处理多个并发通道,从而提高了系统的并发处理能力;

3、提供了更高效的事件通知机制。当向Selector注册Channel时,可以指定我们感兴趣的操作类型(Connect、Accept、Read、Write),只有在这些事件发生时,Selector才会返回,否则就一直阻塞。这样,我们就可以用一个线程去管理多个channel,也就是NIO实现高效的处理方式的基础;

但同时,NIO Selector也有以下几个缺点:

1、对于连接的管理较为复杂,且处理细节需要高度注意;

2、编程较为繁琐,需要一定的经验和能力;

3、自己编写网络框架时,使用NIO Selector需要考虑到众多细节问题,涉及到多线程、使用ByteBuffer等方面;