JAVA NIO是否因持续循环而浪费CPU周期?
问题描述:
代码用于使用单个线程Java I /回声服务器O代表使用NIOJAVA NIO是否因持续循环而浪费CPU周期?
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主线程相同
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();
}
}
代码来等待在该插座.accept()调用。但是NIO不这样做,因为socketChannel.accept()不是阻塞调用。
于是惯于NIO的程序是连续运行的循环?并导致CPU周期浪费?我能否以更好的方式编写程序?对不起,我对JAVA NIO和异步编程非常陌生。
答
在正常IO线程被阻塞上serverSocket.accept()
。
随着NIO线程被阻塞上selector.select()
。
从Selector#select()
的JavaDoc:
此方法执行阻断选择操作。
为什么这个名为 “非阻塞IO”?
其实,你的第一个例子(与普通的IO)有两个阻塞调用:server.accept()
和in.readLine()
。
现在考虑有行为不当的当事人的案件:它打开到服务器的连接,但从来没有发送任何数据。对于正常的IO,服务器线程在in.readLine()
中等待数据到达,并且直到第一个客户端关闭其连接时才能服务任何其他客户端。
对于NIO,图像不同:如果客户端打开连接,则服务器线程会醒来,server.accept()
s连接并使用相同的选择器注册SocketChannel
。然后服务器线程再次通过selector.select()
等待选择器。现在有两种可能性来唤醒服务器线程:或者是另一个客户端连接,或者是第一个客户端发送一些数据。
所以术语“非阻塞IO”并不意味着服务器线程永远不会堵塞 - 这意味着非运行得客户端无法阻止服务器线程永远。
的Java NIO不循环不断。你的代码可能会,但这会是你的代码浪费CPU周期,而不是Java NIO。注意这里没有什么[标签:异步]。 – EJP