亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

Netty4.x 源碼實(shí)戰(zhàn)系列(五):深入淺出學(xué)NioEventLoopGroup

MSchumi / 2811人閱讀

摘要:接下來(lái)的兩篇文章,我將從源碼角度為大家深入淺出的剖析的線程模型工作機(jī)制。我們看一下的源碼通過(guò)的代碼發(fā)現(xiàn),實(shí)現(xiàn)了接口,其內(nèi)部會(huì)通過(guò)指定的默認(rèn)線程工廠來(lái)創(chuàng)建線程,并執(zhí)行相應(yīng)的任務(wù)。至此,初始化完成了。下一篇我們將詳細(xì)介紹,敬請(qǐng)期待。

我們都知道Netty的線程模型是基于React的線程模型,并且我們都知道Netty是一個(gè)高性能的NIO框架,那么其線程模型必定是它的重要貢獻(xiàn)之一。

在使用netty的服務(wù)端引導(dǎo)類(lèi)ServerBootstrap或客戶端引導(dǎo)類(lèi)Bootstrap進(jìn)行開(kāi)發(fā)時(shí),都需要通過(guò)group屬性指定EventLoopGroup, 因?yàn)槭情_(kāi)發(fā)NIO程序,所以我們選擇NioEventLoopGroup。

接下來(lái)的兩篇文章,我將從源碼角度為大家深入淺出的剖析Netty的React線程模型工作機(jī)制。

本篇側(cè)重點(diǎn)是NioEventLoopGroup。

首先我們先回顧一下,服務(wù)端初始化程序代碼(省略非相關(guān)代碼):

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
    ServerBootstrap b = new ServerBootstrap(); 
    b.group(bossGroup, workerGroup);
    
    ... // 已省略非相關(guān)代碼
    
     // 偵聽(tīng)8000端口
     ChannelFuture f = b.bind(8000).sync(); 
    
     f.channel().closeFuture().sync();
} finally {
    workerGroup.shutdownGracefully();
    bossGroup.shutdownGracefully();
}

在分析源碼之前,我們先看看NioEventLoopGroup的類(lèi)繼承結(jié)構(gòu)圖:

初始化bossGroup及workerGroup時(shí),使用了NioEventLoopGroup的無(wú)參構(gòu)造方法,本篇將從此無(wú)參構(gòu)造入手,詳細(xì)分析NioEventLoopGroup的初始化過(guò)程。

首先我們看看NioEventLoopGroup的無(wú)參構(gòu)造方法:

public NioEventLoopGroup() {
    this(0);
}

其內(nèi)部繼續(xù)調(diào)用器構(gòu)造方法,并指定線程數(shù)為0:

public NioEventLoopGroup(int nThreads) {
    this(nThreads, (Executor) null);
}

繼續(xù)調(diào)用另一個(gè)構(gòu)造方法,指定線程為0,且Executor為null:

public NioEventLoopGroup(int nThreads, Executor executor) {
    this(nThreads, executor, SelectorProvider.provider());
}

在此構(gòu)造中,它會(huì)指定selector的輔助類(lèi) "SelectorProvider.provider()",我們繼續(xù)查看它的調(diào)用:

public NioEventLoopGroup(
            int nThreads, Executor executor, final SelectorProvider selectorProvider) {
    this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

此構(gòu)造方法中,初始化了一個(gè)默認(rèn)的選擇策略工廠,用于生成select策略:

public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory) {
    super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}

經(jīng)過(guò)上面一系列的構(gòu)造方法調(diào)用,此時(shí)個(gè)參數(shù)值對(duì)應(yīng)如下:
nThreads:0
executor: null
selectorProvider: SelectorProvider.provider()
selectStrategyFactory: DefaultSelectStrategyFactory.INSTANCE
以及指定了拒絕策略RejectedExecutionHandlers.reject()

接著其會(huì)調(diào)用父類(lèi)MultithreadEventLoopGroup的MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args)構(gòu)造方法

protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
    super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}

此構(gòu)造方法主要做了一件事,就是當(dāng)指定的線程數(shù)為0時(shí),使用默認(rèn)的線程數(shù)DEFAULT_EVENT_LOOP_THREADS,此只是在MultithreadEventLoopGroup類(lèi)被加載時(shí)完成初始化

private static final int DEFAULT_EVENT_LOOP_THREADS;

static {
    DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
            "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

    if (logger.isDebugEnabled()) {
        logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
    }
}

所以根據(jù)代碼,我們得出,如果初始化NioEventLoopGroup未指定線程數(shù)時(shí),默認(rèn)是CPU核心數(shù)*2

接著繼續(xù)調(diào)用父類(lèi)MultithreadEventExecutorGroup的MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args)構(gòu)造方法

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
    this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}

在此構(gòu)造方法中,我們指定了一個(gè)EventExecutor的選擇工廠DefaultEventExecutorChooserFactory,此工廠主要是用于選擇下一個(gè)可用的EventExecutor, 其內(nèi)部有兩種選擇器, 一個(gè)是基于位運(yùn)算,一個(gè)是基于普通的輪詢(xún),它們的代碼分別如下:

基于位運(yùn)算的選擇器PowerOfTwoEventExecutorChooser

private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;

    PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }

    @Override
    public EventExecutor next() {
        return executors[idx.getAndIncrement() & executors.length - 1];
    }
}

基于普通輪詢(xún)的選擇器GenericEventExecutorChooser

private static final class GenericEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;

    GenericEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }

    @Override
    public EventExecutor next() {
        return executors[Math.abs(idx.getAndIncrement() % executors.length)];
    }
}

我們接著回到剛剛的構(gòu)造器,其內(nèi)部會(huì)繼續(xù)調(diào)用MultithreadEventExecutorGroup的另一個(gè)構(gòu)造方法,此構(gòu)造方法是NioEventLoopGroup的核心代碼

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
    
    // 為了便于代碼剖析,以省略非相關(guān)代碼
    
    // 初始化executor
    if (executor == null) {
        executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
    }

    // 初始化EventExecutor
    children = new EventExecutor[nThreads];

    for (int i = 0; i < nThreads; i ++) {
       
            children[i] = newChild(executor, args);
         
    }

    // 生成選擇器對(duì)象
    chooser = chooserFactory.newChooser(children);
}

此構(gòu)造方法主要做了三件事:
1、初始化executor為T(mén)hreadPerTaskExecutor的實(shí)例:
通過(guò)前面的構(gòu)造方法調(diào)用,我們知道executor為null,所以在此構(gòu)造方法中,executor會(huì)被初始化為T(mén)hreadPerTaskExecutor實(shí)例。我們看一下ThreadPerTaskExecutor的源碼:

public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        if (threadFactory == null) {
            throw new NullPointerException("threadFactory");
        }
        this.threadFactory = threadFactory;
    }

    @Override
    public void execute(Runnable command) {
        threadFactory.newThread(command).start();
    }
}

通過(guò)ThreadPerTaskExecutor 的代碼發(fā)現(xiàn),ThreadPerTaskExecutor 實(shí)現(xiàn)了Executor接口,其內(nèi)部會(huì)通過(guò)newDefaultThreadFactory()指定的默認(rèn)線程工廠來(lái)創(chuàng)建線程,并執(zhí)行相應(yīng)的任務(wù)。

2、初始化EventExecutor數(shù)組children
在MultithreadEventExecutorGroup的構(gòu)造方法中我們看到,EventExecutor數(shù)組children初始化時(shí)是通過(guò)newChild(executor, args)實(shí)現(xiàn)的,而newChild的在MultithreadEventExecutorGroup中是個(gè)抽象方法

protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;

根據(jù)最開(kāi)始的類(lèi)繼承結(jié)構(gòu)圖,我們?cè)贜ioEventLoopGroup中找到了newChild的實(shí)現(xiàn)

@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    return new NioEventLoop(this, executor, (SelectorProvider) args[0],
        ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}

所以從此newChild的實(shí)現(xiàn)中,我們可以看出MultithreadEventExecutorGroup的children,其實(shí)就是對(duì)應(yīng)的一組NioEventLoop對(duì)象。 關(guān)于NioEventLoop下一篇會(huì)作詳細(xì)介紹。

3、根據(jù)我們指定的選擇器工廠,綁定NioEventLoop數(shù)組對(duì)象

chooser = chooserFactory.newChooser(children);

在前面的構(gòu)造方法中,我們指定了chooserFactory為DefaultEventExecutorChooserFactory,在此工廠內(nèi)部,會(huì)根據(jù)children數(shù)組的長(zhǎng)度來(lái)動(dòng)態(tài)選擇選擇器對(duì)象,用于選擇下一個(gè)可執(zhí)行的EventExecutor,也就是NioEventLoop。

@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
    if (isPowerOfTwo(executors.length)) {
        return new PowerOfTwoEventExecutorChooser(executors);
    } else {
        return new GenericEventExecutorChooser(executors);
    }
}

至此,NioEventLoopGroup初始化完成了。

通過(guò)上面的代碼分析,在NioEventLoopGroup初始化的過(guò)程中,其實(shí)就是初始化了一堆可執(zhí)行的Executor數(shù)組,然后根據(jù)某種chooser策略,來(lái)選擇下一個(gè)可用的executor。

我們?cè)倩仡櫩偨Y(jié)一下: 
1、NioEventLoopGroup初始化時(shí)未指定線程數(shù),那么會(huì)使用默認(rèn)線程數(shù),
即 線程數(shù) = CPU核心數(shù) * 2;
2、每個(gè)NioEventLoopGroup對(duì)象內(nèi)部都有一組可執(zhí)行的NioEventLoop(NioEventLoop對(duì)象內(nèi)部包含的excutor對(duì)象為T(mén)hreadPerTaskExecutor類(lèi)型)
3、每個(gè)NioEventLoopGroup對(duì)象都有一個(gè)NioEventLoop選擇器與之對(duì)應(yīng),其會(huì)根據(jù)NioEventLoop的個(gè)數(shù),動(dòng)態(tài)選擇chooser(如果是2的冪次方,則按位運(yùn)算,否則使用普通的輪詢(xún))

所以通過(guò)上面的分析,我們得出NioEventLoopGroup主要功能就是為了選擇NioEventLoop,而真正的重點(diǎn)就在NioEventLoop中,它是整個(gè)netty線程執(zhí)行的關(guān)鍵。

下一篇我們將詳細(xì)介紹NioEventLoop,敬請(qǐng)期待。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/68100.html

相關(guān)文章

  • Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解

    摘要:對(duì)于,目前大家只知道是個(gè)線程組,其內(nèi)部到底如何實(shí)現(xiàn)的,它的作用到底是什么,大家也都不太清楚,由于篇幅原因,這里不作詳細(xì)介紹,后面會(huì)有文章作專(zhuān)門(mén)詳解。 在上一篇《ServerBootstrap 與 Bootstrap 初探》中,我們已經(jīng)初步的了解了ServerBootstrap是netty進(jìn)行服務(wù)端開(kāi)發(fā)的引導(dǎo)類(lèi)。 且在上一篇的服務(wù)端示例中,我們也看到了,在使用netty進(jìn)行網(wǎng)絡(luò)編程時(shí),我...

    laoLiueizo 評(píng)論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(一):ServerBootstrap 與 Bootstrap 初探

    摘要:而用于主線程池的屬性都定義在中本篇只是簡(jiǎn)單介紹了一下引導(dǎo)類(lèi)的配置屬性,下一篇我將詳細(xì)介紹服務(wù)端引導(dǎo)類(lèi)的過(guò)程分析。 從Java1.4開(kāi)始, Java引入了non-blocking IO,簡(jiǎn)稱(chēng)NIO。NIO與傳統(tǒng)socket最大的不同就是引入了Channel和多路復(fù)用selector的概念。傳統(tǒng)的socket是基于stream的,它是單向的,有InputStream表示read和Outpu...

    BakerJ 評(píng)論0 收藏0
  • 【自己讀源碼Netty4.X系列(一) 啟動(dòng)類(lèi)概覽

    摘要:一些想法這個(gè)系列想開(kāi)很久了,自己使用也有一段時(shí)間了,利用也編寫(xiě)了一個(gè)簡(jiǎn)單的框架,并運(yùn)用到工作中了,感覺(jué)還不錯(cuò),趁著這段時(shí)間工作不是很忙,來(lái)分析一波源碼,提升下技術(shù)硬實(shí)力。 一些想法 這個(gè)系列想開(kāi)很久了,自己使用netty也有一段時(shí)間了,利用netty也編寫(xiě)了一個(gè)簡(jiǎn)單的框架,并運(yùn)用到工作中了,感覺(jué)還不錯(cuò),趁著這段時(shí)間工作不是很忙,來(lái)分析一波源碼,提升下技術(shù)硬實(shí)力。 結(jié)構(gòu) 這里先看下net...

    qingshanli1988 評(píng)論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(三):NioServerSocketChannel全剖析

    摘要:本篇將通過(guò)實(shí)例化過(guò)程,來(lái)深入剖析。及初始化完成后,它們會(huì)相互連接。我們?cè)诨氐降臉?gòu)造方法父類(lèi)構(gòu)造方法調(diào)用完成后,還要初始化一下自己的配置對(duì)象是的內(nèi)部類(lèi)而又是繼承自,通過(guò)代碼分析,此對(duì)象就是就會(huì)對(duì)底層一些配置設(shè)置行為的封裝。 根據(jù)上一篇《Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解》所述,在進(jìn)行服務(wù)端開(kāi)發(fā)時(shí),必須通過(guò)ServerBootstrap引導(dǎo)類(lèi)的channel方法來(lái)...

    Flink_China 評(píng)論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(四):Pipeline全剖析

    摘要:在上一篇源碼實(shí)戰(zhàn)系列三全剖析中,我們?cè)敿?xì)分析了的初始化過(guò)程,并得出了如下結(jié)論在中,每一個(gè)都有一個(gè)對(duì)象,并且其內(nèi)部本質(zhì)上就是一個(gè)雙向鏈表本篇我們將深入源碼內(nèi)部,對(duì)其一探究竟,給大家一個(gè)全方位解析。 在上一篇《Netty4.x 源碼實(shí)戰(zhàn)系列(三):NioServerSocketChannel全剖析》中,我們?cè)敿?xì)分析了NioServerSocketChannel的初始化過(guò)程,并得出了如下結(jié)論...

    13651657101 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

MSchumi

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<