首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java NIO SocketChannel 實戰:非阻塞 I/O、選擇器與多線程反應器模式

     編輯:Java 綜合教學

NIO 核心組件

  • Channel: SocketChannel、ServerSocketChannel、DatagramChannel。ServerSocketChannel 僅監聽連接,不傳輸數據。
  • Selector: 多路複用器,管理註冊通道的就緒狀態(OP_ACCEPT, OP_READ, OP_WRITE, OP_CONNECT)。
  • SelectionKey: 封裝 Channel 與 Selector 註冊關係,含 interest set(關心操作)與 ready set(就緒操作)。

單線程反應器模式

ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.bind(new InetSocketAddress("localhost", 8888));
ssc.configureBlocking(false);
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
    if (selector.select() == 0) continue;
    for (SelectionKey key : selector.selectedKeys()) {
        if (key.isAcceptable()) {
            SocketChannel sc = ((ServerSocketChannel)key.channel()).accept();
            sc.configureBlocking(false);
            sc.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) {
            SocketChannel sc = (SocketChannel) key.channel();
            ByteBuffer buf = ByteBuffer.allocate(4096);
            StringBuilder sb = new StringBuilder();
            while (sc.read(buf) > 0) {
                buf.flip(); sb.append(new String(buf.array())); buf.clear();
            }
            System.out.println("recv: " + sb);
            key.interestOps(SelectionKey.OP_WRITE);
        } else if (key.isWritable()) {
            SocketChannel sc = (SocketChannel) key.channel();
            ByteBuffer buf = ByteBuffer.wrap(("server: " + Math.random()).getBytes());
            while (buf.hasRemaining()) sc.write(buf);
            key.interestOps(SelectionKey.OP_READ);
        }
        selector.selectedKeys().remove(key);
    }
}

多線程反應器模式(主從 Reactor)

  • 主線程負責 Selector 輪詢分發。
  • 業務處理提交到線程池(讀線程池/寫線程池)。
  • 注意:SelectionKey 非線程安全,需同步或單線程操作註冊/取消。
// 主循環中
if (key.isReadable()) {
    readPool.execute(new ReadTask((SocketChannel)key.channel()));
    key.interestOps(SelectionKey.OP_WRITE);
} else if (key.isWritable()) {
    writePool.execute(new WriteTask((SocketChannel)key.channel()));
    key.interestOps(SelectionKey.OP_READ);
}

完整代碼見原文,包含 ReadTask/WriteTask 實現。

進階要點

  • wakeup() 喚醒阻塞的 select()。
  • 附加對象 key.attach(obj) 傳遞上下文。
  • 取消註冊 key.cancel(),通道關閉自動取消。
  • 內存模型:Heap Buffer vs Direct Buffer (ByteBuffer.allocateDirect)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved