什么是Java中的非阻塞I/O,你能提供一个例子吗?
在Java中,非阻塞I/O是一种I/O模型,它允许程序在等待数据就绪时继续执行其他任务,而不必一直阻塞等待数据的到来。非阻塞I/O通常与多路复用技术(如Java NIO的Selector)结合使用,以实现在单线程或少量线程下处理多个I/O通道的能力。
下面是一个简单的Java非阻塞I/O的示例,使用Java NIO中的ServerSocketChannel和Selector:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;public class NonBlockingServer {public static void main(String[] args) {try {// 创建ServerSocketChannel并绑定端口ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8080));serverSocketChannel.configureBlocking(false); // 设置为非阻塞模式// 创建Selector并注册ServerSocketChannelSelector selector = Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {// 阻塞等待I/O事件发生selector.select();// 获取所有发生的事件Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();iterator.remove();if (key.isAcceptable()) {// 处理连接事件ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverChannel.accept();clientChannel.configureBlocking(false);clientChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {// 处理读取事件SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = clientChannel.read(buffer);if (bytesRead == -1) {clientChannel.close();key.cancel();} else if (bytesRead > 0) {buffer.flip();byte[] data = new byte[buffer.limit()];buffer.get(data);System.out.println("Received: " + new String(data));}}}}} catch (IOException e) {e.printStackTrace();}}
}
在这个例子中,服务器使用了非阻塞I/O模型。它首先创建一个ServerSocketChannel,并将其配置为非阻塞模式。然后,它创建一个Selector并将ServerSocketChannel注册到Selector上,以便监听连接事件。
在主循环中,服务器通过调用selector.select()来阻塞等待I/O事件的发生。一旦有事件发生,服务器会遍历所有发生的事件,并根据事件类型执行相应的操作。如果有新的连接到达(Acceptable事件),服务器会接受连接,并将客户端的SocketChannel注册到Selector上以监听读取事件。如果客户端有数据可读(Readable事件),服务器会读取数据并进行处理。这样,服务器可以在等待数据到达时继续执行其他任务,而不必阻塞等待数据的到来。