<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 的存在!!

          共 2119字,需瀏覽 5分鐘

           ·

          2020-11-04 11:11

          182522f6ca669237b0d22ea1e2c7a5a1.webp

          Java技術(shù)棧

          www.javastack.cn

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



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

          一、FastThreadLocal 簡(jiǎn)介

          FastThreadLocal 并不是 JDK 自帶的,而是在 Netty 中造的一個(gè)輪子,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 是一個(gè)特殊的 ThreadLocal 變體,當(dāng)從線程類 FastThreadLocalThread 中訪問 FastThreadLocalm時(shí)可以獲得更高的訪問性能。如果你還不知道什么是 ThreadLocal,可以關(guān)注公眾號(hào)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ù)了一個(gè)索引常量 index,該常量在每次創(chuàng)建 FastThreadLocal 中都會(huì)自動(dòng)+1,從而保證了下標(biāo)的不重復(fù)性。

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

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

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

          • FastThreadLocalRunnable
          • FastThreadLocalThread
          85f39a3d032c0588aff246e85add53aa.webp

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

          2ee59ce0809b1533fe3475651089acd4.webp

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

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

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


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

          寫一個(gè)測(cè)試小示例:

          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é)果輸出:

          9f9dd70eddce51a2f0654aaf48ce4073.webp

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

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

          7e03479b28ecd02c40ff536c95c41322.webp

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

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

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

          eec43225be65f7fe66fd4e093237ea2e.webp

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

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

          四、總結(jié)

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

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

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

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

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

          8791beef53f78588648690f0f828f965.webp


          2306088d6550223f5dd02442adab3022.webp

          89b2f59114621e395515eeea2620f6b8.webp
          920fcd76424c73a8571a81b968161026.webpd3dcfa07a5eb577b80751235d2b08458.webpbf8b50cc4b579123714bfec1eb8fbf41.webp
          334fd3ab62329adf509b788af29cf3c5.webp



          關(guān)注Java技術(shù)??锤喔韶?/strong>



          8ae27ba13d6931ec8739b15647530f60.webp戳原文,獲取精選面試題!
          瀏覽 40
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  99亚洲婷婷伊人五月天久久欧美 | 人人曰人人操 | 亚洲精品蜜桃 | 三级网站在线免费 | 国产精品爽爽久久久久 |