文章出處

在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

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 AutoPoster 的頭像
    AutoPoster

    互聯網 - 大數據

    AutoPoster 發表在 痞客邦 留言(0) 人氣()