今天來學習Java中的ThreadLocal,也叫做本地變量,主要有如下知識點:數據庫
基本使用
源碼解析
使用場景
ThreadLocal
,不少地方叫作線程本地變量。
ThreadLocal在每一個線程中爲變量建立一個副本,即每一個線程內部都會有一個該變量,且在線程內部任何地方均可以使用,線程之間互不影響,這樣一來就不存在線程安全問題,也不會嚴重影響程序執行性能。安全
ThreadLocal類提供的幾個方法:多線程
public T get() {} public void set(T value) {} public void remove() {} protected T initialValue() {}
get()
方法是用來獲取ThreadLocal在當前線程中保存的變量副本.set()
用來設置當前線程中變量的副本.remove()
用來移除當前線程中變量的副本.initialValue()
是一個protected方法,通常是用來在使用時進行重寫.性能
首先咱們來看一下ThreadLocal類是如何爲每一個線程建立一個變量的副本的。學習
1.先看下get
方法的實現:this
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T) e.value; } return setInitialValue(); }
第一句是取得當前線程,而後經過getMap(t)
方法獲取到一個map,map的類型爲ThreadLocalMap
。
而後接着下面獲取到<key,value>
鍵值對,注意這裏獲取鍵值對傳進去的是this,而不是當前線程t。
若是獲取成功,則返回value值。
若是map爲空,則調用setInitialValue
方法返回value。線程
2.接着看一下getMap
方法中作了什麼:code
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
getMap
中,是調用當前線程t,返回當前線程t中的一個成員變量threadLocals
。對象
3.那麼咱們繼續取Thread類中取看一下成員變量threadLocals
是什麼:繼承
ThreadLocal.ThreadLocalMap threadLocals = null;
實際上就是一個ThreadLocalMap
,這個類型是ThreadLocal類的一個內部類,咱們繼續取看ThreadLocalMap
的實現:
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal> { Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } } }
能夠看到ThreadLocalMap
的Entry繼承了WeakReference,而且使用ThreadLocal做爲鍵值。
4.而後再繼續看setInitialValue
方法的具體實現:
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
很容易瞭解,就是若是map不爲空,就設置鍵值對,爲空,再建立Map,看一下createMap
的實現:
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
至此,可能大部分朋友已經明白了ThreadLocal是如何爲每一個線程建立變量的副本的:
首先,在 每一個線程Thread內部有一個ThreadLocal.ThreadLocalMap類型的成員變量threadLocals,這個threadLocals就是用來存儲實際的變量副本的,key值爲當前ThreadLocal變量,value爲變量副本(即T類型的變量)。
初始時,在Thread裏面,threadLocals爲空,當經過ThreadLocal變量調用get()方法或者set()方法,就會對Thread類中的threadLocals進行初始化,而且 以當前ThreadLocal變量爲鍵值,以ThreadLocal要保存的副本變量爲value,存到threadLocals。而後在當前線程裏面,若是要使用副本變量,就能夠經過get方法在threadLocals裏面查找。
最多見的ThreadLocal使用場景爲用來解決數據庫鏈接、Session管理等。
數據庫鏈接
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>(){ public Connection initialvalue () { return DriverManager.getConnection(DB_URL); } public static Connection getConnection () { return connectionHolder.get(); } };
有關多線程的知識暫時先到這裏,後面有時間再補充!