亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java源碼解析ThreadLocal及使用場(chǎng)景

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

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

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

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

接下來(lái)我們看一下ThreadLocal的源碼。首先是類的介紹。如下圖。這個(gè)類提供了線程本地變量。這些變量使每個(gè)線程都有自己的一份拷貝。ThreadLocal期望能夠管理一個(gè)線程的狀態(tài),例如用戶id或事務(wù)id。例如下面的例子產(chǎn)生線程本地的唯一id。線程的id是第一次調(diào)用時(shí)進(jìn)行復(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è)置為指定的值。大部分子類無(wú)需重寫該方法。首先獲取當(dāng)前線程,然后獲取當(dāng)前線程的ThreadLocalMap。如果ThreadLocalMap不為null,則設(shè)置當(dāng)前線程的值為指定的值,否則調(diào)用createMap方法。

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

寫到這里,自己回想起之前換工作面試時(shí),面試官問(wèn)自己關(guān)于ThreadLocal的實(shí)現(xiàn)原理。那個(gè)時(shí)候,為了準(zhǔn)備面試,自己只在網(wǎng)上看了一些面試題,并沒(méi)有真正掌握,在回答這個(gè)問(wèn)題時(shí),我有印象,自己回答的是用一個(gè)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);
  }

接下來(lái)看一下get方法。

源碼如下。首先獲取當(dāng)前線程的ThreadLocalMap,然后,從ThreadLocalMap獲取該ThreadLocal變量對(duì)應(yīng)的value,然后返回value。如果ThreadLocalMap為null,則說(shuō)明該線程還沒(méi)有設(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;
  }

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

This is the end。

總結(jié)

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

相關(guān)文章

  • Vue.Js及Java實(shí)現(xiàn)文件分片上傳代碼實(shí)例

    Vue.Js及Java實(shí)現(xiàn)文件分片上傳代碼實(shí)例

    這篇文章主要介紹了Vue.Js及Java實(shí)現(xiàn)文件分片上傳代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 解析Hibernate + MySQL中文亂碼問(wèn)題

    解析Hibernate + MySQL中文亂碼問(wèn)題

    如果持久化的類中有包括了漢字的String對(duì)象,那么對(duì)應(yīng)到數(shù)據(jù)庫(kù)中漢字的部分就會(huì)是亂碼。這主要是由于MySQL數(shù)據(jù)表的字符集與我們當(dāng)前使用的本地字符集不相同造成的
    2013-07-07
  • 通過(guò)實(shí)例解析JMM和Volatile底層原理

    通過(guò)實(shí)例解析JMM和Volatile底層原理

    這篇文章主要介紹了通過(guò)實(shí)例解析JMM和Volatile底層原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Java必須學(xué)會(huì)的類的繼承與多態(tài)

    Java必須學(xué)會(huì)的類的繼承與多態(tài)

    這篇文章主要介紹了Java類的繼承與多態(tài)的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-08-08
  • 在idea2023中使用SpringBoot整合Lombok全過(guò)程及詳細(xì)用法

    在idea2023中使用SpringBoot整合Lombok全過(guò)程及詳細(xì)用法

    Lombok項(xiàng)目是一個(gè)java庫(kù),它可以自動(dòng)插入到編輯器和構(gòu)建工具中,增強(qiáng)java的性能,本文詳細(xì)給大家介紹了在idea2023中使用SpringBoot整合Lombok全過(guò)程及詳細(xì)用法,需要的朋友可以參考下
    2023-09-09
  • springboot獲取profile的操作

    springboot獲取profile的操作

    這篇文章主要介紹了springboot獲取profile的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 詳解Springboot應(yīng)用啟動(dòng)以及關(guān)閉時(shí)完成某些操作

    詳解Springboot應(yīng)用啟動(dòng)以及關(guān)閉時(shí)完成某些操作

    這篇文章主要介紹了詳解Springboot應(yīng)用啟動(dòng)以及關(guān)閉時(shí)完成某些操作,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • java?Stream流常見(jiàn)操作方法(反射,類加載器,類加載,反射)

    java?Stream流常見(jiàn)操作方法(反射,類加載器,類加載,反射)

    這篇文章主要介紹了java?Stream流常見(jiàn)操作方法(反射,類加載器,類加載,反射),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-06-06
  • JavaWeb實(shí)現(xiàn)簡(jiǎn)單的自動(dòng)登錄功能

    JavaWeb實(shí)現(xiàn)簡(jiǎn)單的自動(dòng)登錄功能

    這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)簡(jiǎn)單的自動(dòng)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 淺談Maven Wrapper

    淺談Maven Wrapper

    這篇文章主要介紹了淺談Maven Wrapper,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12

最新評(píng)論