ThreadLocal簡單理解


在java開源項目的代碼中看到一個類里ThreadLocal的屬性:
private static ThreadLocal<Boolean> clientMode = new ThreadLocal<>();


印象中在看書的時候見到過ThreadLocal,但突然就想不起它的用處了。。心里一驚感覺當時書白看了。於是馬上網上查了查。

 
原來它的意思是線程的本地變量,ThreadLocal更像是一個線程變量訪問的工具類。
 
那為什么要用這種方法呢?
翻看了《Java並發編程實踐》,看到這么一個說法:線程本地變量通常用於防止可變單例或者全局變量的設計中,出現不正確的共享。
 
感覺這個看着很生硬啊。書中也舉了例子,是JDBC的Connection的應用。Connection對於單線程的程序中,一般會啟動時就創建好,這樣就不用每次都創建對象啦。但是換到多線程環境下就不行了,因為JDBC規范並沒有要求Connection是線程安全的。那么如果要解決就可以使用ThreadLocal。使用ThreadLocal可以在每個線程中創建一個Connection對象,這樣就滿足線程安全要求了。
 
這里比較好奇的是ThreadLocal是如何做到這些的呢?
 
ThreadLocal的實現
打開源代碼,ThreadLocal是個泛型類,里面也並不復雜,看到的構造函數也是什么也沒有做。ThreadLocal中比較常用的方法主要是set和get。最主要的奧秘便是下面這幾行代碼:
private final int threadLocalHashCode = nextHashCode();
 
    /**
     * The next hash code to be given out. Updated atomically. Starts at
     * zero.
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();
 
    /**
     * The difference between successively generated hash codes - turns
     * implicit sequential thread-local IDs into near-optimally spread
     * multiplicative hash values for power-of-two-sized tables.
     */
    private static final int HASH_INCREMENT = 0x61c88647;
 
    /**
     * Returns the next hash code.
     */
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

threadLocalHashCode這個變量會隨着ThreadLocal構造時創建,而初始化它的是一個nextHashCode()方法。從nextHashCode方法便知道是對一個整形變量nextHashCode進行了一個加法運算,而是固定的增加HASH_INCREMENT大小。

 
這樣做是什么意思呢?其實就是每次創建ThreadLocal時都產生一次新的hash值,就是讓每次的對象不一樣。那么有何用處?
 
再看看set方法,因為這個方法是ThreadLocal將變量設置到線程中的方法:
/**
     * 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);
    }

可以看到方法的執行過程:

1、獲得當前線程的實例
2、然后從線程里獲取ThreadLocalMap對象,這就是線程里存本地變量的地方
3、如果map不為空則將value寫入到map中,而key就是當前ThreadLocal的對象
4、如果為null,剛創建map,當然同樣會將value寫入map中,key同樣是ThreadLocal的對象
 
這樣就理解了,其實ThreadLocal每次產生一個新的對象,以此來保證每個線程都針對一個ThreadLocal對象。然后將數據通過set方法向線程中的threadLocals寫入值,以此來保證線程安全。當然在寫入的value必須不是一個共享對象,否則也是無法保證一定線程安全的。
 
 
引用:
《java並發編程實踐》
正確理解ThreadLocal: http://www.iteye.com/topic/103804
 
 
 
注:此文章為原創,歡迎轉載,請在文章頁面明顯位置給出此文鏈接!
若您覺得這篇文章還不錯請點擊下右下角的推薦,非常感謝!
http://www.cnblogs.com/5207


免責聲明!

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



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