成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

追蹤解析 Netty 的 FastThreadLocal 源碼

Anonymous1 / 1104人閱讀

摘要:零前期準(zhǔn)備文章異常啰嗦且繞彎。二是底層真正起作用的類,并且提供了大量的靜態(tài)方法。在普通的線程中,這個(gè)對(duì)象由于本身沒有的原生支持,所以只能附著在對(duì)象當(dāng)中。同一個(gè)線程中如果創(chuàng)建多個(gè)對(duì)象,獲取到的是同一個(gè)。

零 前期準(zhǔn)備 0 FBI WARNING

文章異常啰嗦且繞彎。

1 版本

JDK 版本 : OpenJDK 11.0.1

IDE : idea 2018.3

Netty 版本 : netty-all 4.1.34.Final

2 FastThreadLocal 簡(jiǎn)介

FastThreadLocal 是 Netty 中實(shí)現(xiàn)的高性能 ThreadLocal 工具,功能上和 ThreadLocal 差不多,但是性能上遠(yuǎn)高于 jdk 自帶的 ThreadLocal。

3 Demo
import io.netty.util.concurrent.FastThreadLocal;

public class FastThreadLocalDemo {

    public static void main(String[] args) {

        //創(chuàng)建 FastThreadLocal 對(duì)象
        FastThreadLocal tl = new FastThreadLocal<>();

        //FastThreadLocal 的存入功能
        long setBegin = System.nanoTime();
        tl.set("test");
        long setAfter = System.nanoTime();
        System.out.println("get : " + (setAfter - setBegin));

        //FastThreadLocal 的獲取功能
        long getBegin = System.nanoTime();
        String fastGet = tl.get();
        long getAfter = System.nanoTime();
        System.out.println("get : " + (getAfter - getBegin));

        //FastThreadLocal 的移除功能
        long removeBegin = System.nanoTime();
        tl.remove();
        long removeAfter = System.nanoTime();
        System.out.println("remove : " + (removeAfter - removeBegin));
    }
}
一 FastThreadLocal 的創(chuàng)建

回到 Demo 中的創(chuàng)建代碼:

FastThreadLocal tl = new FastThreadLocal<>();

追蹤 FastThreadLocal 的構(gòu)造器:

//step 1
//FastThreadLocal.class
public FastThreadLocal() {
    //index 是一個(gè) int 類型的變量
    index = InternalThreadLocalMap.nextVariableIndex();
}

//step 2
//InternalThreadLocalMap.class
public static int nextVariableIndex() {
    //nextIndex 是一個(gè)定義在 UnpaddedInternalThreadLocalMap 類中的靜態(tài) AtomicInteger 類型對(duì)象
    //UnpaddedInternalThreadLocalMap 是 InternalThreadLocalMap 的父類
    //這里使用自增操作獲取一個(gè) int 值,并返回
    int index = nextIndex.getAndIncrement();
    if (index < 0) {
        nextIndex.decrementAndGet();
        throw new IllegalStateException("too many thread-local indexed variables");
    }
    return index;
}

其實(shí) FastThreadLocal 的創(chuàng)建就只是獲取一個(gè)唯一的 int 值作為標(biāo)識(shí),沒有其它操作了。

二 InternalThreadLocalMap

InternalThreadLocalMap 是 FastThreadLocal 底層真正起作用的 ThreadLocal 類,并且提供了大量的靜態(tài)方法。

1 獲取對(duì)象

最為核心的是 InternalThreadLocalMap 的 get() 方法:

//InternalThreadLocalMap.class
public static InternalThreadLocalMap get() {
    //獲取當(dāng)前線程的線程對(duì)象
    Thread thread = Thread.currentThread();

    //判斷線程對(duì)象的類型
    if (thread instanceof FastThreadLocalThread) {
        //在 Netty 中使用的 FastThreadLocal 的時(shí)候會(huì)用到該類型的方法
        return fastGet((FastThreadLocalThread) thread);
    } else {
        //正常情況下多帶帶使用 FastThreadLocal,線程對(duì)象不會(huì)是 FastThreadLocalThread
        return slowGet();
    }
}

先來看 fastGet():

//InternalThreadLocalMap.class
private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
    //直接獲取 FastThreadLocalThread 中的 threadLocalMap 對(duì)象并返回即可
    InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
    
    //為空的話新建一個(gè)
    if (threadLocalMap == null) {
        thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
    }
    return threadLocalMap;
}

再來看 slowGet():

//InternalThreadLocalMap.class
private static InternalThreadLocalMap slowGet() {
    //獲取 UnpaddedInternalThreadLocalMap 中的 slowThreadLocalMap 對(duì)象
    //slowThreadLocalMap 是一個(gè)靜態(tài)的 ThreadLocal 類型對(duì)象,儲(chǔ)存的數(shù)據(jù)類型是 InternalThreadLocalMap
    ThreadLocal slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;

    //獲取該對(duì)象中的 InternalThreadLocalMap 對(duì)象實(shí)例并返回
    InternalThreadLocalMap ret = slowThreadLocalMap.get();

    //為空的情況下新建一個(gè)
    if (ret == null) {
        ret = new InternalThreadLocalMap();
        slowThreadLocalMap.set(ret);
    }
    return ret;
}

可以看到實(shí)際上對(duì)于 FastThreadLocal 來說,真正起作用的是 InternalThreadLocalMap 對(duì)象。

在普通的線程中,這個(gè)對(duì)象由于本身沒有 jdk 的原生支持,所以只能附著在 ThreadLocal 對(duì)象當(dāng)中。

但是由于 UnpaddedInternalThreadLocalMap 中的 slowThreadLocalMap 本身是一個(gè)靜態(tài)的 ThreadLocal 對(duì)象,所以不同的線程實(shí)際上調(diào)用到的都是同一個(gè)對(duì)象,但是獲取到的 InternalThreadLocalMap 卻不是同一個(gè)。同一個(gè)線程中如果創(chuàng)建多個(gè) FastThreadLocal 對(duì)象,獲取到的是同一個(gè) InternalThreadLocalMap。

2 set

InternalThreadLocalMap 的底層儲(chǔ)存是一個(gè) Object 數(shù)組,通過 setIndexedVariable(...) 方法儲(chǔ)存進(jìn)去:

//InternalThreadLocalMap.class
public boolean setIndexedVariable(int index, Object value) {
    //indexedVariables 是一個(gè)定義在 UnpaddedInternalThreadLocalMap 中的 Object 數(shù)組
    Object[] lookup = indexedVariables;

    //在這里需要判斷數(shù)組的長(zhǎng)度問題
    //index 是每個(gè) FastThreadLocal 創(chuàng)建的時(shí)候都會(huì)獲取的唯一標(biāo)識(shí)碼,同時(shí)也是數(shù)組上的位置
    if (index < lookup.length) {
        //獲取原值
        Object oldValue = lookup[index];
        //賦值
        lookup[index] = value;
        //UNSET 是一個(gè)靜態(tài)的 Object 對(duì)象,用于默認(rèn)填充 lookup 數(shù)組
        //此處 oldValue 如果等于 UNSET,則證明該位置上原來不存在對(duì)象儲(chǔ)存
        //如果是已經(jīng)儲(chǔ)存過對(duì)象,又調(diào)用該方法替換了一次,會(huì)返回 false
        return oldValue == UNSET;
    } else {
        //數(shù)組擴(kuò)容
        expandIndexedVariableTableAndSet(index, value);
        return true;
    }
}
3 get

InternalThreadLocalMap 中獲取值的方法是通過 indexedVariable(...) 方法:

//InternalThreadLocalMap.class
public Object indexedVariable(int index) {
    //根據(jù) index 從數(shù)組中獲取到想要的位置的值
    Object[] lookup = indexedVariables;
    return index < lookup.length? lookup[index] : UNSET;
}
4 remove

InternalThreadLocalMap 中刪除值的方法是通過 indexedVariable(...) 方法:

//InternalThreadLocalMap.class
public Object removeIndexedVariable(int index) {
    //獲取數(shù)組
    Object[] lookup = indexedVariables;
    if (index < lookup.length) {
        Object v = lookup[index];
        //將指定位置的值替換成 UNSET 對(duì)象
        lookup[index] = UNSET;
        return v;
    } else {
        return UNSET;
    }
}

InternalThreadLocalMap 還有一個(gè)靜態(tài)的 remove() 方法用于清除自身:

//InternalThreadLocalMap.class
public static void remove() {
    Thread thread = Thread.currentThread();
    if (thread instanceof FastThreadLocalThread) {
        ((FastThreadLocalThread) thread).setThreadLocalMap(null);
    } else {
        slowThreadLocalMap.remove();
    }
}

代碼比較簡(jiǎn)單,不做過多分析。

二 存入元素

回到 Demo 中的存入元素的代碼:

tl.set("test");

追蹤 get(...) 方法:

//step 1
//FastThreadLocal.class
public final void set(V value) {
    //先判斷 value 不是 UNSET 對(duì)象
    if (value != InternalThreadLocalMap.UNSET) {
        //獲取 InternalThreadLocalMap 對(duì)象
        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();

        //setKnownNotUnset(...) 方法會(huì)將 value 存入 threadLocalMap 中
        if (setKnownNotUnset(threadLocalMap, value)) {
            //此處會(huì)清理已經(jīng)被 gc 回收的線程對(duì)象所儲(chǔ)存的值
            registerCleaner(threadLocalMap);
        }
    } else {
        remove();
    }
}

//step 2
//FastThreadLocal.class
private boolean setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
    //調(diào)用 setIndexedVariable(...) 方法去存儲(chǔ) value,具體見上方 InternalThreadLocalMap 的詳細(xì)解讀
    if (threadLocalMap.setIndexedVariable(index, value)) {
        //addToVariablesToRemove(...) 方法會(huì)將 FastThreadLocal 對(duì)象存放到 threadLocalMap 中的一個(gè)集合中
        //這個(gè)集合用于在需要的時(shí)候集中銷毀 FastThreadLocal
        addToVariablesToRemove(threadLocalMap, this);
        return true;
    }
    return false;
}
三 獲取元素

回到 Demo 中獲取元素的代碼:

String fastGet = tl.get();

追蹤 set(...) 方法:

//FastThreadLocal.class
public final V get() {
    //獲取 InternalThreadLocalMap 對(duì)象
    InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
    //從 InternalThreadLocalMap 中獲取值
    Object v = threadLocalMap.indexedVariable(index);

    //如果存在值,則直接返回該值即可
    if (v != InternalThreadLocalMap.UNSET) {
        return (V) v;
    }

    //不存在的情況下,initialize(...) 會(huì)返回一個(gè) null 值
    V value = initialize(threadLocalMap);

    //gc 處理
    registerCleaner(threadLocalMap);

    //返回 null
    return value;
}
三 移除元素

回到 Demo 中移除元素的代碼:

String fastGet = tl.get();

追蹤 remove(...) 方法:

//step 1
//FastThreadLocal.class
public final void remove() {
    //InternalThreadLocalMap 的 getIfSet() 方法會(huì)獲取 InternalThreadLocalMap 對(duì)象
    remove(InternalThreadLocalMap.getIfSet());
}

//step 2
//FastThreadLocal.class
public final void remove(InternalThreadLocalMap threadLocalMap) {

    //有效性驗(yàn)證
    if (threadLocalMap == null) {
        return;
    }

    //清除值
    Object v = threadLocalMap.removeIndexedVariable(index);

    //到之前 threadLocalMap 中保存 FastThreadLocal 對(duì)象的集合里去刪除對(duì)象
    removeFromVariablesToRemove(threadLocalMap, this);

    if (v != InternalThreadLocalMap.UNSET) {
        try {
            //此方法為空,是預(yù)留的一個(gè)處理方法,使用者也可以自己做實(shí)現(xiàn)
            onRemoval((V) v);
        } catch (Exception e) {
            PlatformDependent.throwException(e);
        }
    }
}
四 內(nèi)存管理

在真實(shí)的開發(fā)環(huán)境中,可能會(huì)存在一個(gè)線程使用了此 FastThreadLocal,然后線程完成之后被 gc 回收了,但是該 FastThreadLocal 的值沒有被回收的情況。

所以在 FastThreadLocal 中就由一個(gè)防止內(nèi)存泄漏的方法 registerCleaner(...):

//FastThreadLocal.class
private void registerCleaner(final InternalThreadLocalMap threadLocalMap) {

    Thread current = Thread.currentThread();

    //如果 FastThreadLocalThread 被標(biāo)記為要被清理,或者 index 這個(gè)位置的元素并不被收錄于清理目錄下,則直接返回
    if (FastThreadLocalThread.willCleanupFastThreadLocals(current) || threadLocalMap.isCleanerFlagSet(index)) {
        return;
    }

    //將 index 收錄到清理目錄中
    threadLocalMap.setCleanerFlag(index);

    //下方代碼是防止內(nèi)存泄漏的核心代碼,但是已經(jīng)被注釋掉了
    //值得一提的是,在以前的 Netty 版本中是存在的,但是在筆者追蹤的 4.1.34 版本中被注釋掉了
    //根據(jù)解釋,是官方覺得這種處理方式不夠優(yōu)雅,所以暫時(shí)將此段代碼注釋掉了,并且打上了 TODO 字樣

//    ObjectCleaner.register(current, new Runnable() {
//        @Override
//        public void run() {
//            remove(threadLocalMap);
//        }
//   });
}
五 一點(diǎn)嘮叨

FastThreadLocal 對(duì)比 jdk 的原生 ThreadLocal,性能優(yōu)勢(shì)主要表現(xiàn)在以下幾個(gè)方面:

1、Netty 基于自己的業(yè)務(wù)需求,對(duì)線程對(duì)象進(jìn)行了封裝,并在此過程中內(nèi)嵌了對(duì) FastThreadLocal 的支持
2、FastThreadLocal 中省略了 ThreadLocal 中的節(jié)點(diǎn)對(duì)象的組裝和 Hash 值的計(jì)算過程,結(jié)構(gòu)更加簡(jiǎn)單,存、拿過程的效率更高
3、ThreadLocal 對(duì)于內(nèi)存的控制比 FastThreadLocal 更加嚴(yán)謹(jǐn),消耗更多的精力去進(jìn)行內(nèi)存檢查和清理
4、FastThreadLocal 中靜態(tài)(static)方法的使用更加頻繁,是典型的以空間換時(shí)間的做法

本文僅為個(gè)人的學(xué)習(xí)筆記,可能存在錯(cuò)誤或者表述不清的地方,有緣補(bǔ)充

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

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

相關(guān)文章

  • 追蹤解析 ThreadLocal 源碼

    摘要:雖然類名中帶有字樣,但是實(shí)際上并不是接口的子類。是弱連接接口,這意味著如果僅有指向某一類,其任然有可能被回收掉。這里使用弱連接的意義,是為了防止業(yè)務(wù)代碼中置空對(duì)象,但是由于存在連接可達(dá),所以仍然無法回收掉該對(duì)象的情況發(fā)生。 零 前期準(zhǔn)備 0 FBI WARNING 文章異常啰嗦且繞彎。 1 版本 JDK 版本 : OpenJDK 11.0.1 IDE : idea 2018.3 2 T...

    wawor4827 評(píng)論0 收藏0
  • 【源起Netty 外傳】FastThreadLocal怎么Fast?

    摘要:實(shí)現(xiàn)原理淺談幫助理解的示意圖中有一屬性,類型是的靜態(tài)內(nèi)部類。剛剛說過,是一個(gè)中的靜態(tài)內(nèi)部類,則是的內(nèi)部節(jié)點(diǎn)。這個(gè)會(huì)在線程中,作為其屬性初始是一個(gè)數(shù)組的索引,達(dá)成與類似的效果。的方法被調(diào)用時(shí),會(huì)根據(jù)記錄的槽位信息進(jìn)行大掃除。 概述 FastThreadLocal的類名本身就充滿了對(duì)ThreadLocal的挑釁,快男FastThreadLocal是怎么快的?源碼中類注釋坦白如下: /** ...

    gxyz 評(píng)論0 收藏0
  • 談?wù)凧ava引用和Threadlocal那些事

    摘要:容易導(dǎo)致內(nèi)存泄漏。如果我們的強(qiáng)引用不存在的話,那么就會(huì)被回收,也就是會(huì)出現(xiàn)我們沒被回收,被回收,導(dǎo)致永遠(yuǎn)存在,出現(xiàn)內(nèi)存泄漏。緩存行和一次定位,不會(huì)有沖突由于使用數(shù)組,不會(huì)出現(xiàn)回收,沒被回收的尷尬局面,所以避免了內(nèi)存泄漏。 1 背景 某一天在某一個(gè)群里面的某個(gè)群友突然提出了一個(gè)問題:threadlocal的key是虛引用,那么在threadlocal.get()的時(shí)候,發(fā)生GC之后,ke...

    justjavac 評(píng)論0 收藏0
  • 【源起Netty 前傳】Linux網(wǎng)絡(luò)模型小記

    摘要:非阻塞模型這種也很好理解,由阻塞的死等系統(tǒng)響應(yīng)進(jìn)化成多次調(diào)用查看數(shù)據(jù)就緒狀態(tài)。復(fù)用模型,以及它的增強(qiáng)版就屬于該種模型。此時(shí)用戶進(jìn)程阻塞在事件上,數(shù)據(jù)就緒系統(tǒng)予以通知。信號(hào)驅(qū)動(dòng)模型應(yīng)用進(jìn)程建立信號(hào)處理程序時(shí),是非阻塞的。 引言 之前的兩篇文章 FastThreadLocal怎么Fast?、ScheduledThreadPoolExecutor源碼解讀 搞的我心力交瘁,且讀源碼過程中深感功...

    Null 評(píng)論0 收藏0
  • Netty源碼解析

    摘要:一旦某個(gè)事件觸發(fā),相應(yīng)的則會(huì)被調(diào)用,并進(jìn)行處理。事實(shí)上,內(nèi)部的連接處理協(xié)議編解碼超時(shí)等機(jī)制,都是通過完成的。開啟源碼之門理解了的事件驅(qū)動(dòng)機(jī)制,我們現(xiàn)在可以來研究的各個(gè)模塊了。 Netty是什么 大概用Netty的,無論新手還是老手,都知道它是一個(gè)網(wǎng)絡(luò)通訊框架。所謂框架,基本上都是一個(gè)作用:基于底層API,提供更便捷的編程模型。那么通訊框架到底做了什么事情呢?回答這個(gè)問題并不太容易,我們...

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

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

0條評(píng)論

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