Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaNIO是否通过连续循环浪费CPU周期?_Java_Multithreading_Nio - Fatal编程技术网

JavaNIO是否通过连续循环浪费CPU周期?

JavaNIO是否通过连续循环浪费CPU周期?,java,multithreading,nio,Java,Multithreading,Nio,使用单线程java I/O的echo服务器代码 public static void main(String[] args) throws Exception { // create socket int port = 4444; ServerSocket serverSocket = new ServerSocket(port); System.err.println("Started server on port " + port); try {

使用单线程java I/O的echo服务器代码

public static void main(String[] args) throws Exception {

    // create socket
    int port = 4444;
    ServerSocket serverSocket = new ServerSocket(port);
    System.err.println("Started server on port " + port);

    try {

        // repeatedly wait for connections, and process
        while (true) {

            // a "blocking" call which waits until a connection is requested
            Socket clientSocket = serverSocket.accept();
            System.err.println("Accepted connection from client");

            // open up IO streams
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            PrintStream out = new PrintStream(clientSocket.getOutputStream());

            // waits for data and reads it in until connection dies
            // readLine() blocks until the server receives a new line from client
            String s;
            while ((s = in.readLine()) != null) {
                out.print(s);
            }

            // close IO streams, then socket
            System.err.println("Closing connection with client");
            out.close();
            in.close();
            clientSocket.close();
        }
    } finally {
        serverSocket.close();
    }

}
使用NIO编写相同的代码

public static void main(String[] args) throws IOException {
    ServerSocketChannel server = ServerSocketChannel.open();
    server.socket().bind(new InetSocketAddress(PORT_NUMBER));
    server.socket().setReuseAddress(true);
    server.configureBlocking(false);

    Selector selector = Selector.open();
    server.register(selector, SelectionKey.OP_ACCEPT);

    ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
    while (true) {
        int channelCount = selector.select();
        if (channelCount > 0) {
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = keys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();

                if (key.isAcceptable()) {
                    SocketChannel client = server.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ, client.socket().getPort());
                } else if (key.isReadable()) {
                    SocketChannel client = (SocketChannel) key.channel();
                    System.out.println("port: " + key.attachment());
                    if (client.read(buffer) < 0) {
                        key.cancel();
                        client.close();
                    } else {
                        buffer.flip(); // read from the buffer
                          /*
                           * byte[] received = new byte[buffer.remaining()];
                           * buffer.get(received); buffer.clear(); // write into the buffer
                           * buffer.put(received); buffer.flip(); // read from the buffer
                           */
                        client.write(buffer);
                        buffer.clear(); // write into the buffer
                    }
                }
            }
        }
    }
}
这里使用普通的I/O,主线程来了,并在socket.accept调用处等待。但是NIO没有这样做,因为socketChannel.accept不是阻塞调用


那么NIO程序是否会持续运行循环呢?并导致CPU周期的浪费?我能用更好的方式写程序吗。抱歉,我对JAVA NIO和异步编程非常陌生。

在正常IO中,线程在serverSocket.accept上被阻塞

使用NIO时,线程在selector.select上被阻塞

从以下文件的JavaDoc:

此方法执行阻塞选择操作

为什么称之为非阻塞IO

实际上,第一个使用普通IO的示例有两个阻塞调用:server.accept和in.readLine

现在考虑一个行为不良的客户端的情况:它打开到服务器的连接,但从不发送任何数据。使用普通IO时,服务器线程在in.readLine中等待数据到达,并且在第一个客户端关闭连接之前无法为任何其他客户端提供服务

对于NIO,情况就不同了:如果客户端打开连接,服务器线程将被唤醒,server.com将接受连接并使用相同的选择器注册SocketChannel。然后服务器线程通过selector.select再次等待选择器。现在有两种可能唤醒服务器线程:要么是另一个连接的客户端,要么是第一个发送数据的客户端


因此,术语“非阻塞IO”并不意味着服务器线程永远不会被阻塞——它意味着不正常的客户端不能永远阻塞服务器线程。

谢谢Thomas。我不知道Selectorselect是阻塞呼叫。那么,为什么它被称为非阻塞IO,而它的一个API实际上阻塞了-\很抱歉我的无知。@Ajay if添加了一些解释性的文本。我希望能更清楚地说明关于非阻塞IO的观点,否则请不要犹豫,多问一下Hanks,让他解释清楚。我现在明白了。感谢您花时间在我的查询上。JavaNIO不会不断循环。您的代码可能会这样做,但浪费CPU周期的将是您的代码,而不是Java NIO。注意,这里什么都没有。