在《Spring 3.x 企業應用開發實戰》中我看到ThreadLocal這個類,當時本身錯誤的認爲這個類能夠解決併發,還本身總結 編髮中的鎖是「時間換空間」,ThreadLocal類是「空間換時間」,當我看了ThreadLocal的源碼後才發現本身的理解徹底錯了。其實ThreadLocal不是用於解決共享變量的問題的,不是爲了協調線程同步而存在,而是爲了方便每一個線程處理本身的狀態而引入的一個機制。
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). 從中能夠總結出三點: (1)每一個線程都有本身的局部變量 (2)獨立於變量的初始化副本 (3)狀態與某一個線程相關聯
//例1 public class ThreadLocalTest { //建立一個Integer型的線程本地變量 public static final ThreadLocal<Integer> local = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return 0; } }; public static void main(String[] args) throws InterruptedException { Thread[] threads = new Thread[5]; for (int j = 0; j < 5; j++) { threads[j] = new Thread(new Runnable() { public void run() { //獲取當前線程的本地變量,而後累加5次 int num = local.get(); for (int i = 0; i < 5; i++) { num++; } //從新設置累加後的本地變量 local.set(num); System.out.println(Thread.currentThread().getName() + " : " + local.get()); } }, "Thread-" + j); } for (Thread thread : threads) { thread.start(); } } } //執行結果 Thread-0 : 5 Thread-1 : 5 Thread-2 : 5 Thread-3 : 5 Thread-4 : 5
//例2 public class ThreadLocalTest { private static Index num = new Index(); //建立一個Index類型的本地變量 private static ThreadLocal<Index> local = new ThreadLocal<Index>() { @Override protected Index initialValue() { return num; } }; public static void main(String[] args) throws InterruptedException { Thread[] threads = new Thread[5]; for (int j = 0; j < 5; j++) { threads[j] = new Thread(new Runnable() { public void run() { //取出當前線程的本地變量,並累加10000次 Index index = local.get(); for (int i = 0; i < 10000; i++) { index.increase(); } System.out.println(Thread.currentThread().getName() + " : "+ index.num); } }, "Thread-" + j); } for (Thread thread : threads) { thread.start(); } } static class Index { int num; public void increase() { num++; } } } //執行結果 Thread-0 : 11611 Thread-1 : 11613 Thread-2 : 22393 Thread-3 : 30219 Thread-4 : 40219
爲何兩例子會出現不一樣結果,根據代碼咱們能夠看出例1複製的是對象,例2複製的是對象的引用。java
《Spring 3.x 企業應用開發實戰》中對ThreadLocal的簡單實現,其實這個是jdk之前實現的思路,可是存在性能問題,如今已經不這樣實現,你們瞭解下。實現的思路很簡單:在ThreadLocal類中有一個Map,用於存儲每個線程的變量副本,Map中元素的鍵爲線程對象,而值對應線程的變量副本。併發
public class SimpleThreadLocal { private Map valueMap = Collections.synchronizedMap(new HashMap()); public void set(Object newValue) { //①鍵爲線程對象,值爲本線程的變量副本 valueMap.put(Thread.currentThread(), newValue); } public Object get() { Thread currentThread = Thread.currentThread(); //②返回本線程對應的變量 Object o = valueMap.get(currentThread); //③若是在Map中不存在,放到Map中保存起來 if (o == null && !valueMap.containsKey(currentThread)) { o = initialValue(); valueMap.put(currentThread, o); } return o; } public void remove() { valueMap.remove(Thread.currentThread()); } public Object initialValue() { return null; } }
源碼縫隙思路:ThreadLocal中set值,而後get取出值ide
set()方法
性能
public void set(T value) { //獲取當前線程 Thread t = Thread.currentThread(); //獲取ThreadLocalMap ThreadLocalMap map = getMap(t); if (map != null) //map存在在set(key,value),注意key是this,表明當前ThreadLocal實例 map.set(this, value); else //不存在則建立,t是當前線程 createMap(t, value); }
createMap()方法this
//ThreadLocalMap是ThreadLocal內部類 void createMap(Thread t, T firstValue) { //每一個線程都有一個ThreadLocalMap t.threadLocals = new ThreadLocalMap(this, firstValue); }
ThreadLocalMap類
spa
//構造方法 //設置map的key值爲threadLocal對象,value爲參數中的object。 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); }
//對ThreadLocal軟引用 static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
get()方法線程
public T get() { Thread t = Thread.currentThread(); //得到ThreadLocalMap 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(); }
//初始化值 private T setInitialValue() { //初始化爲null T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) //set值 map.set(this, value); else //map不存在則建立 createMap(t, value); return value; }
走讀源碼總結:code
ThreadLocal類中有個內部類ThreadLocalMap,這個Map的key值是threadlocal實例,因此說ThreadLocal爲線程局部變量。orm