java nio cpu select() 与 selectNow() 时的使用问题

java nio cpu usage issues when select() vs selectNow()

我尝试使用 select() 与 selectNow(),差异很大 cpu 如果使用 selectNow(),我知道select() vs selectNow() 是阻塞操作和非阻塞操作,那么如何解决这个问题呢?它是 JDK8 中的错误吗?还是我的代码错误?

public static void main(String args[]) throws IOException {
    Selector selector = Selector.open();
    ServerSocketChannel channel = ServerSocketChannel.open();
    channel.configureBlocking(false);
    channel.socket().bind(new InetSocketAddress(9001));
    channel.register(selector, SelectionKey.OP_ACCEPT);
    System.out.println("The server listened at " + LocalDateTime.now() + " on port 9001");
    Iterator<SelectionKey> iterator;
    SelectionKey key;
    while (true) {
        selector.select();          << ---- Here is the key make CPU usage!
        iterator = selector.selectedKeys().iterator();
        while (iterator.hasNext()) {
            key = iterator.next();
            iterator.remove();

            if (key.isAcceptable()) {
                SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
                String address = (new StringBuilder(sc.socket().getInetAddress().toString())).append(":").append(sc.socket().getPort()).toString().replace("/", "");
                sc.configureBlocking(false);
                sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
                sc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                sc.setOption(StandardSocketOptions.TCP_NODELAY, true);
                sc.register(selector, SelectionKey.OP_READ, address);
                System.out.println("The server accepted at " + LocalDateTime.now() + " from " + address);
            }
            if (key.isReadable()) {
                SocketChannel sc = (SocketChannel) key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
                int read = sc.read(buffer);
                if (read == -1) {
                    key.channel().close();
                    key.cancel();
                } else {
                    Object object = convertByteToObject(buffer.array());
                    System.out.println("The server received at " + LocalDateTime.now() + " from " + key.attachment() + " for " + uptimeHttp.HttpRequestAddress);
                    buffer.clear();
                }
            }
        }
    }
}

当您在紧密循环中调用非阻塞操作时,CPU 将尽可能快地迭代,直到您停止它。这通常意味着您将 100% 的 CPU 花费在执行循环上。

如果您看到的小于 100%,则可能是您正在查看用户 CPU,系统调用可能正在使用 CPU.

的其余部分

问题是使用 selectNow() 会导致 Peter 所建议的紧密循环。也就是说,selectNow() 在特定情况下是一个有趣的选项……例如定时操作。您可以使用 selectNow() 和高精度计时器来强制操作以特定频率发生。这是一个非常具体的情况。

因此,如果您想使用 selectNow(),则必须将其与 Thread.sleep() 或其他等效项配对。