c语言编程笔录

首页 >   > 笔记大全

笔记大全

一文带你读懂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"));
}