返回

IO系列2-洞悉五种IO模型,构建高效网络应用

后端

在互联网时代,IO模型是构建高效网络应用的基础。它决定了网络应用程序与操作系统、网络协议之间的交互方式,对系统的性能、并发能力和可扩展性有着至关重要的影响。

IO模型核心概念

同步与异步

同步IO是指在发出IO操作请求后,调用线程会被阻塞,直到操作完成才继续执行。异步IO则相反,IO操作请求发出后,调用线程不会被阻塞,而是继续执行。当IO操作完成时,系统会通过回调或事件通知调用线程。

阻塞与非阻塞

阻塞IO是指IO操作本身会阻塞调用线程。非阻塞IO则相反,IO操作不会阻塞调用线程。即使IO操作尚未完成,调用线程也可以继续执行。

五种IO模型详解

Java中常用的IO模型有五种:

  1. 同步阻塞IO :最简单的IO模型,IO操作请求发出后调用线程会被阻塞,直到操作完成。
  2. 同步非阻塞IO :改进的IO模型,IO操作本身不会阻塞调用线程,但调用线程需要不断轮询IO状态,直到操作完成。
  3. 异步阻塞IO :IO操作请求发出后调用线程会被阻塞,但IO操作本身不会阻塞调用线程。
  4. 异步非阻塞IO :最先进的IO模型,既不会阻塞IO操作,也不会阻塞调用线程。
  5. NIO (New IO):一种基于事件驱动的非阻塞IO模型,使用NIO Selector可以同时监听多个IO事件,大幅提升并发处理能力。

代码演示:

// 同步阻塞IO
try (Socket socket = new Socket("127.0.0.1", 80)) {
    OutputStream out = socket.getOutputStream();
    out.write("GET /index.html HTTP/1.1\r\n".getBytes());
    out.flush();
    InputStream in = socket.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
}

// 同步非阻塞IO
import java.nio.channels.*;

Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
    int selectedKeys = selector.select();
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    for (SelectionKey key : selectedKeys) {
        if (key.isAcceptable()) {
            SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        } else if (key.isReadable()) {
            // 处理读操作
        } else if (key.isWritable()) {
            // 处理写操作
        }
    }
    selectedKeys.clear();
}

// 异步阻塞IO
import java.nio.channels.*;

AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(80));

serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
    @Override
    public void completed(AsynchronousSocketChannel result, Object attachment) {
        // 处理连接
    }

    @Override
    public void failed(Throwable exc, Object attachment) {
        // 处理失败
    }
});

// 异步非阻塞IO
import java.nio.channels.*;

CompletionHandler<Void, Object> handler = new CompletionHandler<Void, Object>() {
    @Override
    public void completed(Void result, Object attachment) {
        // 处理写操作完成
    }

    @Override
    public void failed(Throwable exc, Object attachment) {
        // 处理写操作失败
    }
};

SocketChannel socketChannel = SocketChannel.open();
socketChannel.write(ByteBuffer.wrap("Hello world".getBytes()), null, handler);

// NIO
import java.nio.channels.*;

Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
    int selectedKeys = selector.select();
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    for (SelectionKey key : selectedKeys) {
        if (key.isAcceptable()) {
            SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        } else if (key.isReadable()) {
            // 处理读操作
        } else if (key.isWritable()) {
            // 处理写操作
        }
    }
    selectedKeys.clear();
}

对比与总结

IO模型 同步/异步 阻塞/非阻塞 优点 缺点
同步阻塞IO 同步 阻塞 简单易用 低并发性
同步非阻塞IO 同步 非阻塞 提高并发性 需要不断轮询IO状态
异步阻塞IO 异步 阻塞 提高并发性 只能处理有限数量的并发连接
异步非阻塞IO 异步 非阻塞 最高并发性 编程复杂度高
NIO 异步 非阻塞 极高的并发性 编程复杂度高,需要系统支持

结语

IO模型是网络编程中的基石,选择合适的IO模型对系统性能和可靠性至关重要。通过理解五种IO模型的原理和优缺点,开发者可以根据应用场景和性能需求,选择最合适的IO模型,构建高效、可靠的网络应用。