最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Netty分布式編碼器寫buffer隊列邏輯剖析

 更新時間:2022年03月29日 14:37:11   作者:向南是個萬人迷  
這篇文章主要介紹了Netty分布式編碼器寫buffer隊列邏輯剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前文傳送門:抽象編碼器MessageToByteEncoder

寫buffer隊列

之前的小節(jié)我們介紹過, writeAndFlush方法其實最終會調(diào)用write和flush方法

write方法最終會傳遞到head節(jié)點, 調(diào)用HeadContext的write方法:

public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    unsafe.write(msg, promise);
}

這里通過unsafe對象的write方法, 將消息寫入到緩存中, 具體的執(zhí)行邏輯, 我們在這個小節(jié)進行剖析

我們跟到AbstractUnsafe的write方法中

public final void write(Object msg, ChannelPromise promise) {
    assertEventLoop();
    //負責(zé)緩沖寫進來的byteBuf
    ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
    if (outboundBuffer == null) {
        safeSetFailure(promise, WRITE_CLOSED_CHANNEL_EXCEPTION);
        ReferenceCountUtil.release(msg);
        return;
    }
    int size;
    try {
        //非堆外內(nèi)存轉(zhuǎn)化為堆外內(nèi)存
        msg = filterOutboundMessage(msg);
        size = pipeline.estimatorHandle().size(msg);
        if (size < 0) {
            size = 0;
        }
    } catch (Throwable t) {
        safeSetFailure(promise, t);
        ReferenceCountUtil.release(msg);
        return;
    }
    //插入寫隊列
    outboundBuffer.addMessage(msg, size, promise);
}

首先看 ChannelOutboundBuffer outboundBuffer = this.outboundBuffer 

ChannelOutboundBuffer的功能就是緩存寫入的ByteBuf

我們繼續(xù)看try塊中的 msg = filterOutboundMessage(msg) 

這步的意義就是將非對外內(nèi)存轉(zhuǎn)化為堆外內(nèi)存

filterOutboundMessage方法方法最終會調(diào)用AbstractNioByteChannel中的filterOutboundMessage方法:

protected final Object filterOutboundMessage(Object msg) {
    if (msg instanceof ByteBuf) {
        ByteBuf buf = (ByteBuf) msg;
        //是堆外內(nèi)存, 直接返回
        if (buf.isDirect()) {
            return msg;
        }
        return newDirectBuffer(buf);
    }
    if (msg instanceof FileRegion) {
        return msg;
    }
    throw new UnsupportedOperationException(
            "unsupported message type: " + StringUtil.simpleClassName(msg) + EXPECTED_TYPES);
}

首先判斷msg是否byteBuf對象, 如果是, 判斷是否堆外內(nèi)存, 如果是堆外內(nèi)存, 則直接返回, 否則, 通過newDirectBuffer(buf)這種方式轉(zhuǎn)化為堆外內(nèi)存

回到write方法中

outboundBuffer.addMessage(msg, size, promise)將已經(jīng)轉(zhuǎn)化為堆外內(nèi)存的msg插入到寫隊列

我們跟到addMessage方法當(dāng)中, 這是ChannelOutboundBuffer中的方法:

public void addMessage(Object msg, int size, ChannelPromise promise) {
    Entry entry = Entry.newInstance(msg, size, total(msg), promise); 
    if (tailEntry == null) { 
        flushedEntry = null;
        tailEntry = entry;
    } else { 
        Entry tail = tailEntry;
        tail.next = entry;
        tailEntry = entry;
    } 
    if (unflushedEntry == null) { 
        unflushedEntry = entry;
    }
    incrementPendingOutboundBytes(size, false);
}

首先通過 Entry.newInstance(msg, size, total(msg), promise) 的方式將msg封裝成entry

然后通過調(diào)整tailEntry, flushedEntry, unflushedEntry三個指針, 完成entry的添加

這三個指針均是ChannelOutboundBuffer的成員變量

flushedEntry指向第一個被flush的entry

unflushedEntry指向第一個未被flush的entry

也就是說, 從flushedEntry到unflushedEntry之間的entry, 都是被已經(jīng)被flush的entry

tailEntry指向最后一個entry, 也就是從unflushedEntry到tailEntry之間的entry都是沒flush的entry

我們回到代碼中:

創(chuàng)建了entry之后首先判斷尾指針是否為空, 在第一次添加的時候, 均是空, 所以會將flushedEntry設(shè)置為null, 并且將尾指針設(shè)置為當(dāng)前創(chuàng)建的entry

最后判斷unflushedEntry是否為空, 如果第一次添加這里也是空, 所以這里將unflushedEntry設(shè)置為新創(chuàng)建的entry

第一次添加如下圖所示

7-3-1

如果不是第一次調(diào)用write方法, 則會進入 if (tailEntry == null) 中else塊:

 Entry tail = tailEntry  這里tail就是當(dāng)前尾節(jié)點

 tail.next = entry  代表尾節(jié)點的下一個節(jié)點指向新創(chuàng)建的entry

 tailEntry = entry  將尾節(jié)點也指向entry

這樣就完成了添加操作, 其實就是將新創(chuàng)建的節(jié)點追加到原來尾節(jié)點之后

第二次添加 if (unflushedEntry == null) 會返回false, 所以不會進入if塊

第二次添加之后指針的指向情況如下圖所示:

7-3-4

以后每次調(diào)用write, 如果沒有調(diào)用flush的話都會在尾節(jié)點之后進行追加

回到代碼中, 看這一步incrementPendingOutboundBytes(size, false)

這步時統(tǒng)計當(dāng)前有多少字節(jié)需要被寫出, 我們跟到這個方法中:

private void incrementPendingOutboundBytes(long size, boolean invokeLater) {
    if (size == 0) {
        return;
    }
    //TOTAL_PENDING_SIZE_UPDATER當(dāng)前緩沖區(qū)里面有多少待寫的字節(jié)
    long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, size);
    //getWriteBufferHighWaterMark() 最高不能超過64k
    if (newWriteBufferSize > channel.config().getWriteBufferHighWaterMark()) {
        setUnwritable(invokeLater);
    }
}

看這一步:

long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, size)

TOTAL_PENDING_SIZE_UPDATER表示當(dāng)前緩沖區(qū)還有多少待寫的字節(jié), addAndGet就是將當(dāng)前的ByteBuf的長度進行累加, 累加到newWriteBufferSize中

在繼續(xù)看判斷 if (newWriteBufferSize > channel.config().getWriteBufferHighWaterMark()) 

 channel.config().getWriteBufferHighWaterMark() 表示寫buffer的高水位值, 默認是64k, 也就是說寫buffer的最大長度不能超過64k

如果超過了64k, 則會調(diào)用setUnwritable(invokeLater)方法設(shè)置寫狀態(tài)

我們跟到setUnwritable(invokeLater)方法中

private void setUnwritable(boolean invokeLater) {
    for (;;) {
        final int oldValue = unwritable;
        final int newValue = oldValue | 1; 
        if (UNWRITABLE_UPDATER.compareAndSet(this, oldValue, newValue)) {
            if (oldValue == 0 && newValue != 0) { 
                fireChannelWritabilityChanged(invokeLater);
            }
            break;
        }
    }
}

這里通過自旋和cas操作, 傳播一個ChannelWritabilityChanged事件, 最終會調(diào)用handler的channelWritabilityChanged方法進行處理

以上就是寫buffer的相關(guān)邏輯,更多關(guān)于Netty分布式編碼器寫buffer隊列的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中ArrayList的8種淺拷貝方式示例代碼

    Java中ArrayList的8種淺拷貝方式示例代碼

    這篇文章主要介紹了Java中ArrayList的8種淺拷貝方式的相關(guān)資料,講解了Java中ArrayList的淺拷貝概念,并詳細分享了八種實現(xiàn)淺拷貝的方法,可以幫助讀者更好地理解和選擇合適的淺拷貝方法,需要的朋友可以參考下
    2025-01-01
  • maven加入spring框架的詳細教程

    maven加入spring框架的詳細教程

    這篇文章主要介紹了maven加入spring框架的詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • 國內(nèi)分布式框架Dubbo使用詳解

    國內(nèi)分布式框架Dubbo使用詳解

    這篇文章主要為大家介紹了國內(nèi)分布式框架Dubbo使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • 詳解Java中的流程控制

    詳解Java中的流程控制

    今天帶大家復(fù)習(xí)Java基礎(chǔ)知識,文中對Java流程控制作了非常詳細的介紹及代碼示例,對正在學(xué)習(xí)Java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • SpringBoot攔截器實現(xiàn)登錄攔截的示例代碼

    SpringBoot攔截器實現(xiàn)登錄攔截的示例代碼

    本文主要介紹了SpringBoot攔截器實現(xiàn)登錄攔截,文中根據(jù)實例編碼詳細介紹的十分詳盡,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • SSH框架網(wǎng)上商城項目第2戰(zhàn)之基本增刪查改、Service和Action的抽取

    SSH框架網(wǎng)上商城項目第2戰(zhàn)之基本增刪查改、Service和Action的抽取

    SSH框架網(wǎng)上商城項目第2戰(zhàn)之基本增刪查改、Service和Action的抽取,感興趣的小伙伴們可以參考一下
    2016-05-05
  • java實現(xiàn)身份證號碼驗證的示例代碼

    java實現(xiàn)身份證號碼驗證的示例代碼

    這篇文章主要為大家詳細介紹了如何利用java語言實現(xiàn)身份證號碼驗證的功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-09-09
  • SpringBoot無法解析parameter參數(shù)問題的解決方法

    SpringBoot無法解析parameter參數(shù)問題的解決方法

    使用最新版的 Springboot 3.2.1(我使用3.2.0)搭建開發(fā)環(huán)境進行開發(fā),調(diào)用接口時出現(xiàn)奇怪的錯,本文小編給大家介紹了SpringBoot無法解析parameter參數(shù)問題的原因及解決方法,需要的朋友可以參考下
    2024-04-04
  • Springboot如何通過路徑映射獲取本機圖片資源

    Springboot如何通過路徑映射獲取本機圖片資源

    項目中對圖片的處理與查看是必不可少的,本文將講解如何通過項目路徑來獲取到本機電腦的圖片資源,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-08-08
  • java 讀取excel內(nèi)容具體代碼

    java 讀取excel內(nèi)容具體代碼

    這篇文章介紹了java 讀取excel內(nèi)容具體代碼,有需要的朋友可以參考一下
    2013-10-10

最新評論

怀化市| 神农架林区| 浦江县| 托克托县| 永春县| 雷波县| 黄冈市| 林州市| 乌兰浩特市| 兴和县| 驻马店市| 宁南县| 新营市| 屏边| 东辽县| 南汇区| 台东县| 泸定县| 西盟| 英吉沙县| 柳江县| 云阳县| 绥中县| 徐汇区| 长子县| 琼结县| 中山市| 福安市| 图木舒克市| 成安县| 新和县| 麻江县| 突泉县| 封开县| 通州市| 壤塘县| 怀安县| 洛扎县| 兴和县| 漳平市| 从江县|