javajvmselectornio

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


I tried to use select() vs selectNow(), the difference is high cpu usage if use selectNow(), i know that select() vs selectNow() are blocking vs non-blocking operations, so how to fix the issue? is it bugs in JDK8? or my code errors?

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();
                }
            }
        }
    }
}

Solution

  • When you call a non blocking operation in a tight loop the CPU will keep iterating as fast as it can until you stop it. This usually means you get 100% of one CPU spent executing the loop.

    If you are seeing less than 100% it might be that you are looking at user CPU and the system calls might be using the rest of the CPU.