ThreadLocal 用法

  • ThreadLocal為解決多線程程序的并發問題提供了一種新的思路。使用這個工具類可以很簡潔地編寫出優美的多線程程序。
  • 當使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。
  • 如果你定義了一個單實例的java bean,它有若干屬性,但是有一個屬性不是線程安全的,比如說HashMap。并且碰巧你并不需要在不同的線程中共享這個屬性,也就是說這個屬性不存在跨線程的意義。那么你不要sychronize這么復雜的東西,ThreadLocal將是你不錯的選擇。

先看一個簡單的示例:

package com.hp.up.test.ThreadLocal;

import java.util.HashMap;
/**
 * Created by haopeng on 2017/12/27 16:45
     */

public class Test2 {

static ThreadLocal<HashMap> map0 = new ThreadLocal<HashMap>(){
    @Override
    protected HashMap initialValue() {
        System.out.println(Thread.currentThread().getName()+"initialValue");
        return new HashMap();
    }
};
public void run(){
    Thread[] runs = new Thread[3];
    for(int i=0;i<runs.length;i++){
        runs[i]=new Thread(new T1(i));
    }
    for(int i=0;i<runs.length;i++){
        runs[i].start();
    }
}
public static class T1 implements Runnable{
    int id;
    public T1(int id0){
        id = id0;
    }
    public void run() {
        System.out.println(Thread.currentThread().getName()+":start");
        HashMap map = map0.get();
        for(int i=0;i<10;i++){
            map.put(i, i+id*100);
            try{
                Thread.sleep(100);
            }catch(Exception ex){
            }
        }
        System.out.println(Thread.currentThread().getName()+':'+map);
    }
}
/**
 * Main
 * @param args
 */
public static void main(String[] args){
    Test2 test = new Test2();
    test.run();
}

}

控制臺打印



可以看到map0 雖然是個靜態變量,但是initialValue被調用了三次,通過debug發現,initialValue是從map0.get處發起的。而且每個線程都有自己的map,雖然他們同時執行。

查看Theadlocal源碼,可以發現get()方法:

/**
 * 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();
}

這說明ThreadLocal確實只有一個變量,但是它內部包含一個map,針對每個thread保留一個entry,如果對應的thread不存在則會調用initialValue。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。