自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

FastThreadLocal 是什么鬼?吊打 ThreadLocal 的存在??!

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

 [[350411]]

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

一、FastThreadLocal 簡(jiǎn)介

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

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

  1. /** 
  2.  * A special variant of {@link ThreadLocal} that yields higher access performance when accessed from a 
  3.  * {@link FastThreadLocalThread}. 
  4.  * <p> 
  5.  * Internally, a {@link FastThreadLocal} uses a constant index in an array, instead of using hash code and hash table
  6.  * to look for a variable.  Although seemingly very subtle, it yields slight performance advantage over using a hash 
  7.  * tableand it is useful when accessed frequently. 
  8.  * </p><p> 
  9.  * To take advantage of this thread-local variable, your thread must be a {@link FastThreadLocalThread} or its subtype. 
  10.  * By defaultall threads created by {@link DefaultThreadFactory} are {@link FastThreadLocalThread} due to this reason. 
  11.  * </p><p> 
  12.  * Note that the fast path is only possible on threads that extend {@link FastThreadLocalThread}, because it requires 
  13.  * a special field to store the necessary state.  An access by any other kind of thread falls back to a regular 
  14.  * {@link ThreadLocal}. 
  15.  * </p> 
  16.  * 
  17.  * @param <V> the type of the thread-local variable 
  18.  * @see ThreadLocal 
  19.  */ 
  20. public class FastThreadLocal<V> { 
  21.  ... 

 

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

二、FastThreadLocal 為什么快?

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

  1. private final int index
  2.  
  3. public FastThreadLocal() { 
  4.     index = InternalThreadLocalMap.nextVariableIndex(); 
  1. public static int nextVariableIndex() { 
  2.     int index = nextIndex.getAndIncrement(); 
  3.     if (index < 0) { 
  4.         nextIndex.decrementAndGet(); 
  5.         throw new IllegalStateException("too many thread-local indexed variables"); 
  6.     } 
  7.     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

 

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

 

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

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

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

  1. <dependency> 
  2.     <groupId>io.netty</groupId> 
  3.     <artifactId>netty-all</artifactId> 
  4.     <version>4.1.52.Final</version> 
  5. </dependency> 

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

  1. import io.netty.util.concurrent.DefaultThreadFactory; 
  2. import io.netty.util.concurrent.FastThreadLocal; 
  3.  
  4. public class FastThreadLocalTest { 
  5.  
  6.     public static final int MAX = 100000; 
  7.  
  8.     public static void main(String[] args) { 
  9.         new Thread(() -> threadLocal()).start(); 
  10.         new Thread(() -> fastThreadLocal()).start(); 
  11.     } 
  12.  
  13.     private static void fastThreadLocal() { 
  14.         long start = System.currentTimeMillis(); 
  15.         DefaultThreadFactory defaultThreadFactory = new DefaultThreadFactory(FastThreadLocalTest.class); 
  16.  
  17.         FastThreadLocal<String>[] fastThreadLocal = new FastThreadLocal[MAX]; 
  18.  
  19.         for (int i = 0; i < MAX; i++) { 
  20.             fastThreadLocal[i] = new FastThreadLocal<>(); 
  21.         } 
  22.  
  23.         Thread thread = defaultThreadFactory.newThread(() -> { 
  24.             for (int i = 0; i < MAX; i++) { 
  25.                 fastThreadLocal[i].set("java: " + i); 
  26.             } 
  27.  
  28.             System.out.println("fastThreadLocal set: " + (System.currentTimeMillis() - start)); 
  29.  
  30.             for (int i = 0; i < MAX; i++) { 
  31.                 for (int j = 0; j < MAX; j++) { 
  32.                     fastThreadLocal[i].get(); 
  33.                 } 
  34.             } 
  35.         }); 
  36.         thread.start(); 
  37.         try { 
  38.             thread.join(); 
  39.         } catch (InterruptedException e) { 
  40.             e.printStackTrace(); 
  41.         } 
  42.  
  43.         System.out.println("fastThreadLocal total: " + (System.currentTimeMillis() - start)); 
  44.     } 
  45.  
  46.     private static void threadLocal() { 
  47.         long start = System.currentTimeMillis(); 
  48.         ThreadLocal<String>[] threadLocals = new ThreadLocal[MAX]; 
  49.  
  50.         for (int i = 0; i < MAX; i++) { 
  51.             threadLocals[i] = new ThreadLocal<>(); 
  52.         } 
  53.  
  54.         Thread thread = new Thread(() -> { 
  55.             for (int i = 0; i < MAX; i++) { 
  56.                 threadLocals[i].set("java: " + i); 
  57.             } 
  58.  
  59.             System.out.println("threadLocal set: " + (System.currentTimeMillis() - start)); 
  60.  
  61.             for (int i = 0; i < MAX; i++) { 
  62.                 for (int j = 0; j < MAX; j++) { 
  63.                     threadLocals[i].get(); 
  64.                 } 
  65.             } 
  66.         }); 
  67.         thread.start(); 
  68.         try { 
  69.             thread.join(); 
  70.         } catch (InterruptedException e) { 
  71.             e.printStackTrace(); 
  72.         } 
  73.  
  74.         System.out.println("threadLocal total: " + (System.currentTimeMillis() - start)); 
  75.     } 
  76.  

結(jié)果輸出:

 

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

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

 

讀寫操作不多時(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)前線程上的所有變量。

 

所以,使用 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)載自微信公眾號(hào)「Java技術(shù)棧」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java技術(shù)棧公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: Java技術(shù)棧
相關(guān)推薦

2015-11-12 10:03:34

前端H5web

2021-11-10 12:13:02

HostonlyCookie瀏覽器

2020-09-27 06:53:57

MavenCDNwrapper

2017-04-03 15:35:13

知識(shí)體系架構(gòu)

2021-09-13 15:17:52

FastThreadL源碼Java

2015-03-17 10:13:52

HTML5什么鬼

2019-10-30 10:13:15

區(qū)塊鏈技術(shù)支付寶

2021-07-06 10:17:07

Python LaunLinuxWindows

2015-09-29 09:47:14

2022-01-12 12:35:36

Linuxworkqueue工作隊(duì)列

2021-10-11 08:58:34

Goroutine操作系統(tǒng)

2024-09-29 08:57:25

2019-01-07 12:40:19

2015-09-22 09:25:16

RTORPO災(zāi)備技術(shù)

2021-01-07 05:22:47

MySQL字段存儲(chǔ)

2022-09-07 08:41:57

SpringIstio分布式

2022-05-11 08:53:13

MySQL鎖機(jī)制

2015-07-16 10:49:31

虛擬化容器技術(shù)

2019-01-17 14:35:01

2018-01-16 08:47:23

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)