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

Java源碼解析ThreadLocal及使用場景

 更新時間:2019年01月08日 09:06:12   作者:李燦輝  
今天小編就為大家分享一篇關(guān)于Java源碼解析ThreadLocal及使用場景,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧

ThreadLocal是在多線程環(huán)境下經(jīng)常使用的一個類。

這個類并不是為了解決多線程間共享變量的問題。舉個例子,在一個電商系統(tǒng)中,用一個Long型變量表示某個商品的庫存量,多個線程需要訪問庫存量進行銷售,并減去銷售數(shù)量,以更新庫存量。在這個場景中,是不能使用ThreadLocal類的。

ThreadLocal適用的場景是,多個線程都需要使用一個變量,但這個變量的值不需要在各個線程間共享,各個線程都只使用自己的這個變量的值。這樣的場景下,可以使用ThreadLocal。此外,我們使用ThreadLocal還能解決一個參數(shù)過多的問題。例如一個線程內(nèi)的某個方法f1有10個參數(shù),而f1調(diào)用f2時,f2又有10個參數(shù),這么多的參數(shù)傳遞十分繁瑣。那么,我們可以使用ThreadLocal來減少參數(shù)的傳遞,用ThreadLocal定義全局變量,各個線程需要參數(shù)時,去全局變量去取就可以了。

接下來我們看一下ThreadLocal的源碼。首先是類的介紹。如下圖。這個類提供了線程本地變量。這些變量使每個線程都有自己的一份拷貝。ThreadLocal期望能夠管理一個線程的狀態(tài),例如用戶id或事務(wù)id。例如下面的例子產(chǎn)生線程本地的唯一id。線程的id是第一次調(diào)用時進行復(fù)制,并且在后面的調(diào)用中保持不變。

This class provides thread-local variables. 
These variables differ from their normal counterparts in that each thread that accesses
 one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that
 wish to associate state with a thread (e.g., a user ID or Transaction ID).
For example, the class below generates unique identifiers local to each thread.
 A thread's id is assigned the first time it invokes ThreadId.get() and 
remains unchanged on subsequent calls.
  import java.util.concurrent.atomic.AtomicInteger;
  public class ThreadId {
    // Atomic integer containing the next thread ID to be assigned
    private static final AtomicInteger nextId = new AtomicInteger(0);
    // Thread local variable containing each thread's ID
    private static final ThreadLocal<Integer> threadId =
      new ThreadLocal<Integer>() {
        @Override protected Integer initialValue() {
          return nextId.getAndIncrement();
      }
    };
    // Returns the current thread's unique ID, assigning it if necessary
    public static int get() {
      return threadId.get();
    }
  }
Each thread holds an implicit reference to its copy of a thread-local 
variable as long as the thread is alive and the ThreadLocal instance is 
accessible; after a thread goes away, all of its copies of thread-local
 instances are subject to garbage collection (unless other references to 
these copies exist).

下面看一下set方法。

set方法的作用是,把線程本地變量的當(dāng)前線程的拷貝設(shè)置為指定的值。大部分子類無需重寫該方法。首先獲取當(dāng)前線程,然后獲取當(dāng)前線程的ThreadLocalMap。如果ThreadLocalMap不為null,則設(shè)置當(dāng)前線程的值為指定的值,否則調(diào)用createMap方法。

獲取線程的ThreadLocalMap對象,是直接返回的線程的threadLocals,類型為ThreadLocalMap。也就是說,每個線程都有一個ThreadLocalMap對象,用于保存該線程關(guān)聯(lián)的所有的ThreadLocal類型的變量。ThreadLocalMap的key是ThreadLocal,value是該ThreadLocal對應(yīng)的值。具體什么意思呢?在程序中,我們可以定義不止一個ThreadLocal對象,一般會有多個,比如定義3個ThreadLocal<String>,再定義2個ThreadLocal<Integer>,而每個線程可能都需要訪問全部這些ThreadLocal的變量,那么,我們用什么數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)呢?當(dāng)然,最好的方式就是像源碼中的這樣,每個線程有一個ThreadLocalMap,key為ThreadLocal變量名,而value為該線程在該ThreadLocal變量的值。這個設(shè)計實在是太巧妙了。

寫到這里,自己回想起之前換工作面試時,面試官問自己關(guān)于ThreadLocal的實現(xiàn)原理。那個時候,為了準備面試,自己只在網(wǎng)上看了一些面試題,并沒有真正掌握,在回答這個問題時,我有印象,自己回答的是用一個map,線程的id值作為key,變量值作為value,誒,露餡了啊。

  /**
   * Sets the current thread's copy of this thread-local variable
   * to the specified value. Most subclasses will have no need to
   * override this method, relying solely on the {@link #initialValue}
   * method to set the values of thread-locals.
   * @param value the value to be stored in the current thread's copy of
   *    this thread-local.
   **/
  public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
      map.set(this, value);
    else
      createMap(t, value);
  }
  /**
   * Get the map associated with a ThreadLocal. Overridden in
   * InheritableThreadLocal.
   * @param t the current thread
   * @return the map
   **/
  ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
  }
  /**
   * Create the map associated with a ThreadLocal. Overridden in
   * InheritableThreadLocal.
   * @param t the current thread
   * @param firstValue value for the initial entry of the map
   **/
  void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
  }

接下來看一下get方法。

源碼如下。首先獲取當(dāng)前線程的ThreadLocalMap,然后,從ThreadLocalMap獲取該ThreadLocal變量對應(yīng)的value,然后返回value。如果ThreadLocalMap為null,則說明該線程還沒有設(shè)置該ThreadLocal變量的值,那么就返回setInitialValue方法的返回值。其中的initialValue方法的返回值,通常情況下為null。但是,子類可以重寫initialValue方法以返回期望的值。

  /**
   * Returns the value in the current thread's copy of this
   * thread-local variable. If the variable has no value for the
   * current thread, it is first initialized to the value returned
   * by an invocation of the {@link #initialValue} method.
   * @return the current thread's value of this thread-local
   **/
  public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
      ThreadLocalMap.Entry e = map.getEntry(this);
      if (e != null) {
        @SuppressWarnings("unchecked")
        T result = (T)e.value;
        return result;
      }
    }
    return setInitialValue();
  }
  /**
   * Variant of set() to establish initialValue. Used instead
   * of set() in case user has overridden the set() method.
   * @return the initial value
   **/
  private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
      map.set(this, value);
    else
      createMap(t, value);
    return value;
  }
  protected T initialValue() {
    return null;
  }

文章的最后,簡單介紹一下ThreadLocalMap這個類,該類是ThreadLocal的靜態(tài)內(nèi)部類。它對HashMap進行了改造,用于保存各個ThreadLocal變量和某線程的該變量的值的映射關(guān)系。每個線程都有一個ThreadLocalMap類型的屬性。ThreadLocalMap中的table數(shù)組的長度,與該線程訪問的ThreadLocal類型變量的個數(shù)有關(guān),而與別的無關(guān)。

This is the end。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接

相關(guān)文章

  • Mybatis批量提交實現(xiàn)步驟詳解

    Mybatis批量提交實現(xiàn)步驟詳解

    這篇文章主要介紹了Mybatis批量提交實現(xiàn)步驟詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-12-12
  • Java在重載中使用Object的問題

    Java在重載中使用Object的問題

    這篇文章主要介紹了Java在重載中使用Object的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 詳解基于MybatisPlus兩步實現(xiàn)多租戶方案

    詳解基于MybatisPlus兩步實現(xiàn)多租戶方案

    這篇文章主要介紹了詳解基于MybatisPlus兩步實現(xiàn)多租戶方案,本文分兩步,通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 關(guān)于Jar包部署命令全面解析

    關(guān)于Jar包部署命令全面解析

    這篇文章主要介紹了Jar包部署命令全面解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Java8?Stream?流常用方法合集

    Java8?Stream?流常用方法合集

    這篇文章主要介紹了?Java8?Stream?流常用方法合集,Stream?是?Java8?中處理集合的關(guān)鍵抽象概念,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作,下文相關(guān)資料,需要的朋友可以參考一下
    2022-04-04
  • Java多線程編程之讀寫鎖ReadWriteLock用法實例

    Java多線程編程之讀寫鎖ReadWriteLock用法實例

    這篇文章主要介紹了Java多線程編程之讀寫鎖ReadWriteLock用法實例,本文直接給出編碼實例,需要的朋友可以參考下
    2015-05-05
  • Java 手寫LRU緩存淘汰算法

    Java 手寫LRU緩存淘汰算法

    本文主要講了如何通過哈希鏈表這種數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)LRU算法,提供了三種實現(xiàn)思路,第一種從雙向鏈表開始,借助于HashMap來實現(xiàn)滿足要求的LRUCache
    2021-05-05
  • Spring自定義注解實現(xiàn)接口版本管理

    Spring自定義注解實現(xiàn)接口版本管理

    這篇文章主要介紹了Spring自定義注解實現(xiàn)接口版本管理,RequestMappingHandlerMapping類是與 @RequestMapping相關(guān)的,它定義映射的規(guī)則,即滿足怎樣的條件則映射到那個接口上,需要的朋友可以參考下
    2023-11-11
  • Java基本語法小白入門級

    Java基本語法小白入門級

    Java基本語法就是指java中的規(guī)則,也是一種語言規(guī)則,規(guī)范,同時也能讓您在后面的學(xué)習(xí)中避免不必要的一些錯誤和麻煩,是您學(xué)好java必修的第一門課程
    2023-05-05
  • SpringBoot中的Mybatis依賴問題

    SpringBoot中的Mybatis依賴問題

    這篇文章主要介紹了SpringBoot中的Mybatis依賴問題,包括pom導(dǎo)入依賴和相關(guān)實例代碼講解,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04

最新評論

大姚县| 泰来县| 安泽县| 安新县| 望都县| 荥阳市| 白水县| 门源| 牡丹江市| 苏尼特右旗| 大兴区| 临海市| 金塔县| 桃江县| 横山县| 古交市| 定州市| 顺平县| 南郑县| 阆中市| 石楼县| 那坡县| 苏尼特右旗| 周宁县| 武威市| 颍上县| 镇雄县| 乌拉特后旗| 柯坪县| 外汇| 平阳县| 揭西县| 马边| 天柱县| 禹城市| 泰宁县| 新泰市| 通辽市| 澜沧| 巫山县| 云霄县|