Selector 简介

2024-05-06 09:17:05 浏览数 (1)

为什么会出现Selector

在阻塞模式下,相关方法(如ServerSocketChannel.acceptSocketChannel.read)会导致线程暂停。当没有连接建立或没有数据可读时,线程会处于等待状态,尽管此时线程不占用CPU资源,但线程本身处于闲置状态。

阻塞模式的缺点

  • 线程暂停:在没有连接或数据可读时,线程会被暂停。
  • 资源闲置:线程在等待期间不执行任何有用工作,导致资源浪费。

非阻塞模式

使用Java NIO,我们可以将通道(Channel)设置为非阻塞模式。在这种模式下,即使在没有连接建立或没有数据可读时,相关方法也会立即返回,而不是让线程暂停。

非阻塞模式的优点

  • 线程不会暂停:在没有连接或数据可读时,线程可以继续执行其他任务。
  • 提高资源利用率:线程在等待期间可以执行其他有用工作。

非阻塞模式的缺点

  • CPU占用:由于线程需要不断轮询通道状态,这可能导致CPU占用率过高。
  • 数据复制时的阻塞:尽管线程在等待数据写入Channel时不会被阻塞,但在数据实际从内核空间复制到用户空间时,线程仍然是阻塞的。

Selector 和 Channel 关系

Selector(选择器)是Java NIO中的一个核心组件,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写或已连接。通过Selector,我们可以实现单线程管理多个channels,即管理多个网络连接。

使用Selector的好处

  • 减少线程数量:使用更少的线程来处理多个channels,减少了线程上下文切换的开销。
  • 提高响应速度:当某个channel有事件发生时,Selector能够立即感知并处理。
  • 高效利用资源:线程在等待期间可以处理其他事件,提高了资源的利用率。

注意事项

  • 多路复用仅适用于网络IO:普通文件IO无法利用多路复用。
  • 避免无效轮询:使用Selector时,需要确保只有当有事件发生时才去处理,避免无效的轮询操作。

示例Demo

代码语言:java复制
// 1. 创建Selector  
Selector selector = Selector.open();  
  
// 2. 配置ServerSocketChannel为非阻塞模式,并注册到Selector  
ServerSocketChannel ssc = ServerSocketChannel.open();  
ssc.configureBlocking(false);  
ssc.bind(new InetSocketAddress(8080));  
ssc.register(selector, SelectionKey.OP_ACCEPT);  
  
// 3. 处理事件循环  
while (true) {  
    // 等待事件发生  
    int readyChannels = selector.select();  
    if (readyChannels == 0) continue;  
  
    // 遍历所有就绪的Channel  
    Set<SelectionKey> selectedKeys = selector.selectedKeys();  
    Iterator<SelectionKey> keyIterator = selectedKeys.iterator();  
    while (keyIterator.hasNext()) {  
        SelectionKey key = keyIterator.next();  
        if (key.isAcceptable()) {  
            // 处理新连接  
        } else if (key.isReadable()) {  
            // 读取数据  
        }  
        // ... 其他事件处理  
  
        // 移除已处理的Key,避免重复处理  
        keyIterator.remove();  
    }  
}

0 人点赞