一文带你读懂Java IO复用
更新时间:2023-11-30什么是Java IO复用
Java IO复用是一种允许多个IO操作共享同一个操作系统资源的技术。在传统的Java IO中,每个IO读写操作都将阻塞线程,直到读写完成或遇到异常为止。这种方式在高并发环境下会导致性能问题,因为每个IO操作都需要启动一个新线程。Java IO复用则通过将多个IO读写操作注册到同一个选择器中,从而共享线程和操作系统资源。
Java IO复用的机制
Java IO复用机制的核心是选择器。选择器(Selector)是一种能够检查多个通道上是否有IO事件,如读写事件、连接事件等的组件,当一个通道发生读写事件时,它的读写事件会通知选择器,选择器再将 IO事件分发给准备就绪的通道
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
InetSocketAddress hostAddress = new InetSocketAddress("localhost", 8080);
serverSocket.bind(hostAddress);
serverSocket.configureBlocking(false);
int operations = SelectionKey.OP_ACCEPT;
SelectionKey selectKy = serverSocket.register(selector, operations, null);
Java IO复用的优势
Java IO复用技术能很好地解决多线程的性能问题,带来了以下好处:
1. 节省了线程资源。一个选择器线程可以检查多个通道,所以不需要启动多个线程执行IO操作。
2. 更好的扩展性。在CPU负载不高的情况下,大多数线程将处于等待状态。使用IO复用,您可以更有效地使用系统资源,处理更多的IO事件
while (true){
int readyChannels = selector.select();
if (readyChannels == 0) continue;
Set selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()){
SelectionKey key = keyIterator.next();
if(key.isAcceptable()) {
// a connection was accepted by a ServerSocketChannel.
//do something...
} else if (key.isReadable()) {
// a channel is ready for reading
//do something...
} else if (key.isWritable()) {
// ....
}
keyIterator.remove();
}
}
Java IO复用的应用场景
Java IO复用技术最常用于实现 NIO(非阻塞式IO)。NIO允许您在单个线程内处理多个通道,从而更有效地处理并发和IO操作。NIO可用于网络编程,例如开发高性能的Web服务器
private void read(SelectionKey key) throws Exception {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
long bytesRead = socketChannel.read(buffer);
if(bytesRead == -1){
System.out.println("client closed connection, so closing selec...");
key.cancel();
socketChannel.close();
return;
}
buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
System.out.println(new String(data, "UTF-8"));
}