Java中ThreadLocal的深入理解


官方對ThreadLocal的描述:

  "該類提供了線程局部(thread-local)變量。這些變量不同於它們的普通對應物,因為訪問某個變量(通過其get或set方法)的每個線程都有自己的局部變量,它獨立於變量的初始化副本。ThreadLocal實例通常是類中的private static字段,它們希望將狀態與某一個線程(例如,用戶ID或事物ID)相關聯。"

《Thinking in Java》中的描述:

  防止任務在共享資源上產生沖突的第二種方式是根除對變量的共享。線程本地存儲是一種自動化機制,可以為使用變量的每個不同的線程都創建不同的存儲。因此,如果你有5個線程都要使用變量x所表示的對象,那線程本地存儲就會生成5個用於x的不同的存儲塊。主要是,它們使得你可以將狀態與線程關聯起來。

三個要點:

  1.每個線程都有自己的局部變量

    每個線程都有一個獨立於其它線程的上下文來保存這個變量,一個線程的本地變量對其它線程是不可見的。

  2.獨立於變量的初始化副本

    ThreadLocal可以給一個初始值,而每個線程都會獲得這個初始化值的一個副本,這樣才能保證不同的線程都有一份拷貝。

  3.狀態與某一個線程相關聯

    ThreadLocal不是用於解決共享變量的問題的,不是為了協調線程同步而存在,而是為了方便每個線程處理自己的狀態而引入的一個機制,就像《Thinking in Java》中描述的那樣:”它們使得你可以將狀態與線程關聯起來。“理解這點對正確使用ThreadLocal至關重要。

源碼舉例:

  從輸出的結果可以看出,五個線程處理自己的本地變量值。

  而這個測試的結果,並沒有相同。這是因為實例為對象,所以初始值為一個對象的引用,那么五個線程的副本就是這個對象的引用的副本,也就是說這些引用還是指向同一個對象,所以就出現了這種情況。

ThreadLocal的接口方法:

  • void set(T value):設置當前線程的線程局部變量的值;
 1 public void set(T value) {
 2    Thread t = Thread.currentThread();
 3    ThreadLocalMap map = getMap(t);
 4 
 5    if (map != null)
 6      map.set(this, value);
 7   //說明線程第一次使用線程本地變量(注意這里的第一次含義)
 8    else
 9        createMap(t, value);
10 }
  • public T get():該方法返回當前線程所對應的線程局部變量;
 1 public T get() {
 2   //獲取當前執行線程
 3   Thread t = Thread.currentThread();
 4   //取得當前線程的ThreadLocalMap實例
 5   ThreadLocalMap map = getMap(t);
 6   //如果map不為空,說明該線程已經有了一個ThreadLocalMap實例
 7   if (map != null) {
 8     //map中保存線程的所有的線程本地變量,我們要去查找當前線程本地變量
 9     ThreadLocalMap.Entry e = map.getEntry(this);
10     //如果當前線程本地變量存在這個map中,則返回其對應的值
11     if (e != null)
12          return (T)e.value;
13   }
14    //如果map不存在或者map中不存在當前線程本地變量,返回初始值
15    return setInitialValue();
16 }
  • public void remove():將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK 5.0新增的方法。當線程結束后,對應該線程的局部變量將被自動垃圾回收,所以顯示調用該方法清除線程的局部變量並不是必須的操作,但它可以加快內存回收的速度;
  • protected T initialValue():返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的,這個方法是一個延遲調用方法,在線程第1次調用get()或set(T)時才執行,並且僅執行1次。ThreadLocal中的默認實現直接返回一個null。

       這里注意,ThreadLocal中是有一個Map,但這個Map不是我們平時使用的Map,而是ThreadLocalMap,ThreadLocalMap是ThreadLocal的一個內部類,不對外使用的。當使用ThreadLocal存值時,首先是獲取到當前線程對象,然后獲取到當前線程本地變量Map,最后將當前使用的ThreadLocal和傳入的值放到Map中,也就是說ThreadLocalMap中存的值是[ThreadLocal對象, 存放的值]這樣做的好處是,每個線程都對應一個本地變量的Map,所以一個線程可以存在多個線程本地變量。下面提供一個簡單的實現版本:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM