亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Netty中線程名稱的示例分析

發布時間:2021-12-28 15:30:59 來源:億速云 閱讀:127 作者:小新 欄目:大數據

小編給大家分享一下Netty中線程名稱的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

NioEventLoop創建過程.
創建的第一個步驟就是創建線程執行器ThreadPerTaskExecutor, 這個線程執行器就是用來創建Netty底層的線程的. 在學習Java的Thread時候,線程默認名稱類似thread-0,thread-1,thread-2...以此類推. 而線程的名稱對于我們排查問題的時候也是起到很大作用的, 因此我們在設計線程池, 也會根據一定的規則給線程池中的線程命名, 這也是一個好的習慣.
在Netty中自然也會給線程池中的線程命名, 接下來我們就分析下它的命名規則.

Netty中線程名稱的示例分析

上面的圖中有兩個線程池,一個叫bossGroup,另一個叫workerGroup. 它們都屬于EventLoopGroup類型. 前面我們也提高過, bossGroup負責接收客戶端請求, workerGroup猶如其名一樣, 是個'工人',負責處理客戶端的IO讀寫操作的.

在這兩個Group內部有很多個NioEventLoop

Netty中線程名稱的示例分析

如果我們在創建EventLoopGroup時, 沒有傳線程數量, 那么每個線程池默認創建  2*CPU個線程.
每個線程的命名規則:  nioEventLoop-n-n, 例如nioEventLoop-2-1

接下來我們解釋下后面兩個數字如何確定的.

我們就拿nioEventLoop-2-1這個為例

備注: 包括dubbo, RocketMQ這樣的框架在內, 它們底層在使用Netty時的代碼類似, 如下

EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();
上面的代碼主線程main從上往下執行的時候, 第一個bossGroup是第1個線程池, 第二個workerGroup是第2個線程池. 依次類推, 如果代碼里new了5個NioEventLoopGroup, 那么第五個group就是第5個線程池.
因此我們示例中的nioEventLoop-2-1的數字2就表示第2個線程池的意思. 也就是nioEventLoop-2-1這個名字的線程是在第2個線程池中的.

Netty中線程名稱的示例分析

我們繼續分析nioEventLoop-2-1中數字1的由來.

每個EventLoopGroup中有多個NioEventLoop. 當NioEventLoop在啟動的時候會創建底層的線程.根據  選擇器EventExecutorChooser, 從線程池中第一個被選擇出來為客戶端提供服務的NioEventLoop就是第1個線程, 從線程池中第二個被選擇出來為客戶端提供服務的NioEventLoop就是第2個線程, 以此類推.  所以示例nioEventLoop-2-1中的數字1就是表示線程池中的第1個線程, 整體就表示第2個線程池中的第1個線程.

Netty中線程名稱的示例分析

備注: 示例nioEventLoop-2-1中的nioEventLoop這個名字是固定的.


實戰

接下來我們從實際去看下它們的名字

服務端代碼如下


import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelPipeline;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;import io.netty.handler.codec.FixedLengthFrameDecoder;import io.netty.handler.codec.string.StringDecoder;import io.netty.handler.codec.string.StringEncoder;import io.netty.handler.logging.LogLevel;import io.netty.handler.logging.LoggingHandler;import io.netty.handler.timeout.IdleStateHandler;
import java.util.concurrent.TimeUnit;
public class Server {

   public static void main(String[] args) throws Exception {
       EventLoopGroup bossGroup = new NioEventLoopGroup(1);        EventLoopGroup workerGroup = new NioEventLoopGroup();
       ServerBootstrap serverBootstrap = new ServerBootstrap();
        try {            serverBootstrap.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                                        .handler(new LoggingHandler(LogLevel.INFO))                    .childHandler(new ChannelInitializer<NioSocketChannel>() {                        @Override                        protected void initChannel(NioSocketChannel ch) {
                           ChannelPipeline channelPipeline = ch.pipeline();                                                        // ...                        }                    });
           // 綁定端口 同步等待成功            ChannelFuture channelFuture1 = serverBootstrap.bind("127.0.0.1", 8080).sync();
           // 等待服務端監聽端口關閉            channelFuture1.channel().closeFuture().sync();        } finally {            // 執行到此處說明服務端已經關閉            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();                }
   }
}

我們把上面的代碼啟動, 然后通過telnet 127.0.0.1 8080方式連接服務器. 我們使用JDK自帶的jvisualvm查看線程.

Netty中線程名稱的示例分析

通過telnet連接

Netty中線程名稱的示例分析

Netty中線程名稱的示例分析

我們發現多了兩個線程, 因為我們通過telnet連接了兩次, 所以多了兩個線程. 其中第二個數字一個是-1, 另一個是-2,表示第1個和第2個線程的意思.

但是

根據上面的服務端代碼和前面的講解, 我們明明創建了兩個線程池, 那么第一個數字應該是-1和-2才對, 可是我們實際觀察發現, 卻是-2和-3. (更準確的說, nioEventLoopGroup-2表示bossGroup, nioEventLoopGroup-3表示workerGroup). 我們的代碼明明只是new出來2個NioEventLoopGroup, 現在實際觀察卻發現nioEventLoopGroup-1被別人占了.

我們從源碼中尋找答案

當我們在代碼中通過new實例化NioEventLoopGroup時, 由于NioEventLoopGroup繼承MultithreadEventExecutorGroup, 所以這個MultithreadEventExecutorGroup也會被實例化.

Netty中線程名稱的示例分析

從圖中我們發現, 會實例化一個DefaultPromise, 其中有個GlobalEventExecutor.INSTANCE. 使用單例模式創建GlobalEventExecutor. 其中GlobalEventExecutor有個屬性

final ThreadFactory threadFactory = new DefaultThreadFactory(DefaultThreadFactory.toPoolName(getClass()), false, Thread.NORM_PRIORITY, null);

再跟蹤下DefaultThreadFactory

Netty中線程名稱的示例分析

我們看右下角發現了真相, -1被globalEventExecutor-1-使用了.

備注: DefaultThreadFactory這個工廠類在創建bossGroup和workerGroup都會被使用.

以上是“Netty中線程名稱的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

额尔古纳市| 定南县| 河东区| 华宁县| 琼中| 昌江| 常宁市| 西安市| 石城县| 应用必备| 神池县| 左贡县| 砚山县| 奉化市| 皮山县| 榆树市| 山阳县| 盐山县| 耒阳市| 深圳市| 财经| 杭锦旗| 江陵县| 达孜县| 宁陕县| 青河县| 湾仔区| 旬邑县| 寿阳县| 育儿| 阿拉尔市| 阜康市| 黑山县| 达日县| 天门市| 东海县| 九龙城区| 合江县| 修水县| 德州市| 开化县|