JavaNIO是否通过连续循环浪费CPU周期?
使用单线程java I/O的echo服务器代码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 {
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。注意,这里什么都没有。