<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          FastThreadLocal 是什么鬼?吊打 ThreadLocal 的存在?。?/h1>

          共 2204字,需瀏覽 5分鐘

           ·

          2020-11-07 04:10

          Java技術(shù)棧

          www.javastack.cn

          關(guān)注閱讀更多優(yōu)質(zhì)文章



          ThreadLocal 大家都知道是線程本地變量,今天棧長再介紹一個神器:FastThreadLocal,從字面上看就是:Fast + ThreadLocal,一個快的 ThreadLocal?這到底是什么鬼呢?

          一、FastThreadLocal 簡介

          FastThreadLocal 并不是 JDK 自帶的,而是在 Netty 中造的一個輪子,Netty 為什么要重復(fù)造輪子呢?

          來看下它源碼中的注釋定義:

          /**
          ?*?A?special?variant?of?{@link?ThreadLocal}?that?yields?higher?access?performance?when?accessed?from?a
          ?*?{@link?FastThreadLocalThread}.
          ?*?


          ?*?Internally,?a?{@link?FastThreadLocal}?uses?a?constant?index?in?an?array,?instead?of?using?hash?code?and?hash?table,
          ?*?to?look?for?a?variable.??Although?seemingly?very?subtle,?it?yields?slight?performance?advantage?over?using?a?hash
          ?*?table,?and?it?is?useful?when?accessed?frequently.
          ?*?


          ?*?To?take?advantage?of?this?thread-local?variable,?your?thread?must?be?a?{@link?FastThreadLocalThread}?or?its?subtype.
          ?*?By?default,?all?threads?created?by?{@link?DefaultThreadFactory}?are?{@link?FastThreadLocalThread}?due?to?this?reason.
          ?*?


          ?*?Note?that?the?fast?path?is?only?possible?on?threads?that?extend?{@link?FastThreadLocalThread},?because?it?requires
          ?*?a?special?field?to?store?the?necessary?state.??An?access?by?any?other?kind?of?thread?falls?back?to?a?regular
          ?*?{@link?ThreadLocal}.
          ?*?


          ?*
          ?*?@param??the?type?of?the?thread-local?variable
          ?*?@see?ThreadLocal
          ?*/

          public?class?FastThreadLocal<V>?{
          ?...
          }

          FastThreadLocal 是一個特殊的 ThreadLocal 變體,當(dāng)從線程類 FastThreadLocalThread 中訪問 FastThreadLocalm時可以獲得更高的訪問性能。如果你還不知道什么是 ThreadLocal,可以關(guān)注公眾號Java技術(shù)棧閱讀我之前分享的文章。

          二、FastThreadLocal 為什么快?

          在 FastThreadLocal 內(nèi)部,使用了索引常量代替了 Hash Code 和哈希表,源代碼如下:

          private?final?int?index;

          public?FastThreadLocal()?{
          ????index?=?InternalThreadLocalMap.nextVariableIndex();
          }
          public?static?int?nextVariableIndex()?{
          ????int?index?=?nextIndex.getAndIncrement();
          ????if?(index?????????nextIndex.decrementAndGet();
          ????????throw?new?IllegalStateException("too?many?thread-local?indexed?variables");
          ????}
          ????return?index;
          }

          FastThreadLocal 內(nèi)部維護(hù)了一個索引常量 index,該常量在每次創(chuàng)建 FastThreadLocal 中都會自動+1,從而保證了下標(biāo)的不重復(fù)性。

          這要做雖然會產(chǎn)生大量的 index,但避免了在 ThreadLocal ?中計(jì)算索引下標(biāo)位置以及處理 hash 沖突帶來的損耗,所以在操作數(shù)組時使用固定下標(biāo)要比使用計(jì)算哈希下標(biāo)有一定的性能優(yōu)勢,特別是在頻繁使用時會非常顯著,用空間換時間,這就是高性能 Netty 的巧妙之處。

          要利用 FastThreadLocal 帶來的性能優(yōu)勢,就必須結(jié)合使用 FastThreadLocalThread 線程類或其子類,因?yàn)?FastThreadLocalThread 線程類會存儲必要的狀態(tài),如果使用了非 FastThreadLocalThread 線程類則會回到常規(guī) ThreadLocal。

          Netty 提供了繼承類和實(shí)現(xiàn)接口的線程類:

          • FastThreadLocalRunnable
          • FastThreadLocalThread

          Netty 也提供了 DefaultThreadFactory 工廠類,所有由 DefaultThreadFactory 工廠類創(chuàng)建的線程默認(rèn)就是 FastThreadLocalThread 類型,來看下它的創(chuàng)建過程:

          先創(chuàng)建 FastThreadLocalRunnable,再創(chuàng)建 FastThreadLocalThread,基友搭配,干活不累,一定要配合使用才“快”。

          三、FastThreadLocal 實(shí)戰(zhàn)

          要使用 FastThreadLocal 就需要導(dǎo)入 Netty 的依賴了:


          ????io.netty
          ????netty-all
          ????4.1.52.Final

          寫一個測試小示例:

          import?io.netty.util.concurrent.DefaultThreadFactory;
          import?io.netty.util.concurrent.FastThreadLocal;

          public?class?FastThreadLocalTest?{

          ????public?static?final?int?MAX?=?100000;

          ????public?static?void?main(String[]?args)?{
          ????????new?Thread(()?->?threadLocal()).start();
          ????????new?Thread(()?->?fastThreadLocal()).start();
          ????}

          ????private?static?void?fastThreadLocal()?{
          ????????long?start?=?System.currentTimeMillis();
          ????????DefaultThreadFactory?defaultThreadFactory?=?new?DefaultThreadFactory(FastThreadLocalTest.class);

          ????????FastThreadLocal[]?fastThreadLocal?=?new?FastThreadLocal[MAX];

          ????????for?(int?i?=?0;?i?????????????fastThreadLocal[i]?=?new?FastThreadLocal<>();
          ????????}

          ????????Thread?thread?=?defaultThreadFactory.newThread(()?->?{
          ????????????for?(int?i?=?0;?i?????????????????fastThreadLocal[i].set("java:?"?+?i);
          ????????????}

          ????????????System.out.println("fastThreadLocal?set:?"?+?(System.currentTimeMillis()?-?start));

          ????????????for?(int?i?=?0;?i?????????????????for?(int?j?=?0;?j?????????????????????fastThreadLocal[i].get();
          ????????????????}
          ????????????}
          ????????});
          ????????thread.start();
          ????????try?{
          ????????????thread.join();
          ????????}?catch?(InterruptedException?e)?{
          ????????????e.printStackTrace();
          ????????}

          ????????System.out.println("fastThreadLocal?total:?"?+?(System.currentTimeMillis()?-?start));
          ????}

          ????private?static?void?threadLocal()?{
          ????????long?start?=?System.currentTimeMillis();
          ????????ThreadLocal[]?threadLocals?=?new?ThreadLocal[MAX];

          ????????for?(int?i?=?0;?i?????????????threadLocals[i]?=?new?ThreadLocal<>();
          ????????}

          ????????Thread?thread?=?new?Thread(()?->?{
          ????????????for?(int?i?=?0;?i?????????????????threadLocals[i].set("java:?"?+?i);
          ????????????}

          ????????????System.out.println("threadLocal?set:?"?+?(System.currentTimeMillis()?-?start));

          ????????????for?(int?i?=?0;?i?????????????????for?(int?j?=?0;?j?????????????????????threadLocals[i].get();
          ????????????????}
          ????????????}
          ????????});
          ????????thread.start();
          ????????try?{
          ????????????thread.join();
          ????????}?catch?(InterruptedException?e)?{
          ????????????e.printStackTrace();
          ????????}

          ????????System.out.println("threadLocal?total:?"?+?(System.currentTimeMillis()?-?start));
          ????}

          }

          結(jié)果輸出:

          可以看出,在大量讀寫面前,寫操作的效率差不多,但讀操作 FastThreadLocal 比 ThreadLocal 快的不是一個數(shù)量級,簡直是秒殺 ThreadLocal 的存在。

          當(dāng)我把 MAX 值調(diào)整到 1000 時,結(jié)果輸出:

          讀寫操作不多時,ThreadLocal 明顯更勝一籌!

          上面的示例是單線程測試多個 *ThreadLocal,即數(shù)組形式,另外,我也測試了多線程單個 *ThreadLocal,這時候 FastThreadLocal 效率就明顯要落后于 ThreadLocal。。

          最后需要說明的是,在使用完 FastThreadLocal 之后不用 remove 了,因?yàn)樵?FastThreadLocalRunnable 中已經(jīng)加了移除邏輯,在線程運(yùn)行完時會移除全部綁定在當(dāng)前線程上的所有變量。

          所以,使用 FastThreadLocal 導(dǎo)致內(nèi)存溢出的概率會不會要低于 ThreadLocal?

          不一定,因?yàn)?FastThreadLocal 會產(chǎn)生大量的 index 常量,所謂的空間換時間,所以感覺 FastThreadLocal 內(nèi)存溢出的概率更大,但好在每次使用完都會自動 remove。

          四、總結(jié)

          Netty 中的 FastThreadLocal 在大量頻繁讀寫操作時效率要高于 ThreadLocal,但要注意結(jié)合 Netty 自帶的線程類使用,這可能就是 Netty 為什么高性能的奧妙之一吧!

          如果沒有大量頻繁讀寫操作的場景,JDK 自帶的 ThreadLocal 足矣,并且性能還要優(yōu)于 FastThreadLocal。

          好了,今天的分享就到這里了,覺得有用,轉(zhuǎn)發(fā)分享一下哦。

          最后,Java 系列教程還會繼續(xù)更新,關(guān)注Java技術(shù)棧公眾號第一時間推送,還可以在公眾號菜單中獲取歷史 Java 教程,都是干貨。

          版權(quán)申明:本文系公眾號 "Java技術(shù)棧" 原創(chuàng),原創(chuàng)實(shí)屬不易,轉(zhuǎn)載、引用本文內(nèi)容請注明出處,禁止抄襲、洗稿,請自重,尊重他人勞動成果和知識產(chǎn)權(quán)。






          關(guān)注Java技術(shù)棧看更多干貨



          戳原文,獲取精選面試題!
          瀏覽 67
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報

          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品无码无卡无需播放器 | 草肉肉XXXXHD劉亦菲 | 天天天操操 | 特一级黄色片 | 成人乱妇无码AV在线 |