<bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>
    Fork me on GitHub

    滴滴面試:談談你對Netty線程模型的理解?

    Netty 線程模型是指 Netty 框架為了提供高性能、高并發的網絡通信,而設計的管理和利用線程的策略和機制。

    Netty 線程模型被稱為 Reactor(響應式)模型/模式,它是基于 NIO 多路復用模型的一種升級,它的核心思想是將 IO 事件和業務處理進行分離,使用一個或多個線程來執行任務的一種機制。

    1.Reactor三大組件

    Reactor 包含以下三大組件:
    image.png
    其中:

    1. Reactor(反應器):Reactor 負責監聽和分發事件,它是整個 Reactor 模型的調度中心。Reactor 監視一個或多個輸入通道,如監聽套接字上的連接請求或讀寫事件。當檢測到事件發生時,Reactor 會將其分發給預先注冊的處理器(Handler)進行處理。在 Netty 中,這個角色經常是由 EventLoop 或其相關的 EventLoopGroup 來扮演,它們負責事件的循環處理、任務調度和 I/O 操作。
    2. Acceptor(接收器):用于處理 IO 連接請求。當 Reactor 檢測到有新的客戶端連接請求時,會通知 Acceptor,后者通過 accept() 方法接受連接請求,并創建一個新的 SocketChannel(在 Netty 中是 Channel)來表示這個連接。隨后,Acceptor 通常會將這個新連接的 Channel 注冊到 Worker Reactor 或 EventLoop 中,以便進一步處理該連接上的讀寫事件。
    3. Handlers(處理器):Handlers 負責具體的事件處理邏輯,即執行與事件相關的業務操作。在 Netty 中,Handler 是一個或多個 ChannelHandler 的實例,它們形成一個責任鏈(ChannelPipeline),每個 Handler 負責處理一種或一類特定的事件(如解碼、編碼、業務邏輯處理等)。數據或事件在 ChannelPipeline 中從一個 Handler 傳遞到下一個,直至處理完畢或被消費。Handler 可以分為入站(inbound)和出站(outbound)兩種,分別處理流入的數據或流出的數據。

    2.Reactor三大模型

    Reactor 模式支持以下三大模型:

    1. 單線程模型
    2. 多線程模型
    3. 主從多線程模型

    具體內容如下。

    2.1 單線程模型

    在單線程模型中,所有的事件處理操作都由單個 Reactor 實例在單個線程下完成。Reactor 負責監控事件、分發事件和執行事件處理程序(Handlers),如下圖所示:
    image.png
    單線程模型的實現 Demo 如下:

    // 假設有一個單線程的Reactor,負責監聽、接收連接、讀寫操作
    class SingleThreadReactor {
        EventLoop eventLoop; // 單個事件循環線程
        
        SingleThreadReactor() {
            eventLoop = new EventLoop(); // 初始化單個事件循環
        }
        
        void start(int port) {
            ServerSocketChannel serverSocket = ServerSocketChannel.open();
            serverSocket.socket().bind(new InetSocketAddress(port)); // 綁定端口
            
            eventLoop.execute(() -> { // 在事件循環中執行
                while (true) {
                    SocketChannel clientSocket = serverSocket.accept(); // 接受連接
                    if (clientSocket != null) {
                        handleConnection(clientSocket); // 處理連接
                    }
                }
            });
            eventLoop.run(); // 啟動事件循環
        }
        
        void handleConnection(SocketChannel clientSocket) {
            // 讀寫操作,這里簡化處理
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (clientSocket.read(buffer) > 0) {
                // 處理讀取的數據
                buffer.flip();
                // 假設處理數據邏輯...
                buffer.clear();
            }
            // 寫操作邏輯類似
        }
    }
    

    優缺點分析

    • 優點:簡單、線程安全性好、適合編寫簡單的網絡應用。
    • 缺點:處理能力受限于單個線程的處理能力,無法充分利用多核 CPU,可能會影響性能。

    2.2 多線程模型

    在多線程模型中,連接 Acceptor 和業務處理(Handlers)是由不同線程分開執行的,其中 Handlers 是由線程池(多個線程)來執行的,如下圖所示:
    image.png
    多線程模型的實現 Demo 如下:

    // 假設有兩個線程,一個用于監聽連接,一個用于處理連接后的操作
    class MultiThreadReactor {
        EventLoop acceptLoop;
        EventLoop workerLoop;
        
        MultiThreadReactor() {
            acceptLoop = new EventLoop(); // 接收連接的線程
            workerLoop = new EventLoop(); // 處理連接的線程
        }
        
        void start(int port) {
            ServerSocketChannel serverSocket = ServerSocketChannel.open();
            serverSocket.socket().bind(new InetSocketAddress(port));
            
            acceptLoop.execute(() -> { // 在接受線程中監聽
                while (true) {
                    SocketChannel clientSocket = serverSocket.accept();
                    if (clientSocket != null) {
                        workerLoop.execute(() -> handleConnection(clientSocket)); // 將新連接交給工作線程處理
                    }
                }
            });
            
            acceptLoop.run(); // 啟動接受線程
            workerLoop.run(); // 啟動工作線程
        }
        
        // handleConnection 方法與單線程模型中的相同
    }
    

    優缺點分析

    • 優點:此模式可以提高并發性能,充分利用多核 CPU,并且保持簡單的編程模型。
    • 缺點:多線程數據共享和數據同步比較復雜,并且 Reactor 需要處理所有事件監聽和響應,在高并發場景依然會出現性能瓶頸。

    2.3 主從多線程模型

    主從多線程模型是一個主 Reactor 線程加多個子 Reactor 子線程,以及多個工作線程池來處理業務的,如下圖所示:

    主從多線程模型的實現 Demo 如下:

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    public class MainReactorModel {
        public static void main(String[] args) {
            // 主Reactor,用于接受連接
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            // 從Reactor,用于處理連接后的讀寫操作
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                ServerBootstrap bootstrap = new ServerBootstrap();
                bootstrap.group(bossGroup, workerGroup)
                         .channel(NioServerSocketChannel.class)
                         .childHandler(new ChannelInitializer<SocketChannel>() {
                             @Override
                             protected void initChannel(SocketChannel ch) {
                                 // 在這里添加業務處理器,如解碼器、編碼器、業務邏輯處理器
                                 ch.pipeline().addLast(new MyBusinessHandler());
                             }
                         });
    
                ChannelFuture future = bootstrap.bind(8080).sync();
                System.out.println("Server started at port 8080");
                future.channel().closeFuture().sync(); // 等待服務器關閉
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    

    優缺點分析

    • 優點:可以充分利用多核 CPU 的資源,提高系統的整體性能和并發處理能力。
    • 缺點:模型相對復雜,實現和維護成本較高。

    課后思考

    NioEventLoop 是如何實現的?它能夠保證 Channel 操作的線程安全嗎?為什么?

    本文已收錄到我的面試小站 www.javacn.site,其中包含的內容有:Redis、JVM、并發、并發、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、設計模式、消息隊列等模塊。

    posted @ 2024-05-31 14:52  磊哥|www.javacn.site  閱讀(104)  評論(1編輯  收藏  舉報
    免费视频精品一区二区_日韩一区二区三区精品_aaa在线观看免费完整版_世界一级真人片
    <bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>