把對象封裝到一個線程裏,只有一個線程能夠看到該對象,那麼就算這個對象不是線程安全的,也不會出現任何線程問題,由於它只能在一個線程中被訪問。
ThreadLocal
類來實現線程封閉,這個類使線程中的某個值與保存值的對象關聯起來核心的五個操做:建立,建立並賦初始值,賦值,取值,刪除
private final static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>;
private final static ThreadLocal<String> threadLocal=new ThreadLocal<String>(){ @Override protected String initialValue() { return "入門小站"; } };
threadLocal.set("入門小站");
threadLocal.get();
threadLocal.remove();
首先ThreadLocal
是一個泛型類,保證能夠接受任何類型的對象。一個線程內能夠存在多個
ThreadLocal
,ThreadLocal
內部維護了一個Map
,這個Map
不是HashMap
,而是ThreadLocal
實現的一個ThreadLocalMap
的靜態內部類。咱們使用的get()
,set()
方法實際上是調用了這個ThreadLocalMap
類對應的get()
,set()
。安全
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(); } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
調用ThreadLocal
的set方法時,先獲取當前的線程Thread t = Thread.currentThread();
,而後獲取當前線程維護的ThreadLocalMap
。若是ThreadLocalMap
不存在則初始化。
ThreadLocalMap
的map.set(this, value);
第一個參數是this
,this
指的是當前的ThreadLocal
,就是上面代碼裏面的threadLocal
變量。微信最終的變量是放在當前線程的
ThreadLocalMap
中,並非存在ThreadLocal
上,ThreadLocal
能夠理解成傳遞關係的。多線程
ThreadLocalMap
中使用的key
爲ThreadLocal
的弱引用,弱引用的特色是,若是這個對象只存在弱引用,那麼在下一次垃圾回收的時候必然會被清理掉。因此
ThreadLocal
沒有被強引用的狀況下,在垃圾回收的時候會被清理掉,可是value
倒是強引用,不會被清理,這樣的話就出出現key
爲null
的value
。併發
ThreadLocalMap
實現中已經考慮了這個狀況,在調用set
,get
,remove
方法的時候會清理掉key
爲null
的記錄。若是出現了內存泄漏,那就是說在key
爲null
後,沒有手動調用remove
方法,而且以後也再也不調用set
,get
,remove
方法。app
將ThreadLocal變量定義成private static的,這樣的話ThreadLocal的生命週期就更長,因爲一直存在ThreadLocal的強引用,因此ThreadLocal也就不會被回收,也就能保證任什麼時候候都能根據ThreadLocal的弱引用訪問到Entry的value值,而後remove它,防止內存泄露。ide
在ThreadLocal類中,還包含了一個static修飾的AtomicInteger([əˈtɒmɪk]提供原子操做的Integer類)成員變量(即類變量)和一個static final 修飾的常量(做爲兩個相鄰nextHashCode的差值)。因爲nextHashCode是類變量,因此每一次調用ThreadLocal類均可以保證nextHashCode被更新到新的值,而且下一次調用ThreadLocal類這個被更新的值仍然可用,同時AtomicInteger保證了nextHashCode自增的原子性。
ThreadLocal
應用
Web
項目公共參數從controller層傳遞到service層,再從service層傳遞到mapper層,或者從service層傳遞到其餘的工具類當中。爲了不參數複雜的傳遞,在controller中將已經封裝好的參數放入ThreadLocal中,在其餘層調用時直接經過ThreadLocal對象獲取。在方法結束時,定義攔截器(HandlerInterceptorAdapter)(或者Filter)進行ThreadLocal的remove方法。
在須要登陸的系統中用戶信息經常存在Session
和token
。好比咱們要從Session
中獲取用戶信息須要在接口參數中加上HttpServletRequest對象,而後調用 getSession方法,且每個須要用戶信息的接口都要加上這個參數,才能獲取Session,比較麻煩。這個時候咱們就能夠用
ThreadLocal
,在攔截器(HandlerInterceptorAdapter)(或者Filter)中解析獲取用戶信息,而後保存到ThreadLocal
,業務邏輯直接在ThreadLocal
中獲取就能夠了。工具
【關注微信公衆號:【入門小站】解鎖更多知識點】this