您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關ThreadLocal的基本定義是什么,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
官方釋義: http://docs.oracle.com/javase/8/docs/api/
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).
首先,每個線程都有變量的一個本地獨立副本,保證線程之間的數據不會互相影響
可以通過重寫initialValue()方法實現ThreadLocal的默認初始值
protected static final ThreadLocal<String> TL_EXAMPLE = new ThreadLocal<String>() { @Override protected String initialValue() { return "default"; } };
為什么說明中建議定義為靜態static方法呢?不了解ThreadLocal原理的同學可能就糊涂了,既然是需要滿足多線程并發的,怎么會定義為一個靜態的類成員變量呢?
只要大家看一下ThreadLocal的源碼就了解了,它有個靜態內部類叫ThreadLocalMap<ThreadLocal, Object>, 此Map在Thread類中被定義為了一個類成員變量,即每個Thread線程中都有一個獨立ThreadLocalMap副本,它的值只能被當前線程讀取和修改
想像一下某個類中定義了多個ThreadLocal<?>變量,在當前線程中通過ThreadLocalMap.get(ThreadLocal)獲取到相應的變量副本。
所以ThreadLocal變量本身不是副本,你可以把他當成一個代理,而ThreadLocalMap中存放了線程內的一個一個線程副本,ThreadLocal只是ThreadLocalMap內弱引用的Key(在ThreadLocal對象失效時可以及時的清理ThreadLocalMap)。
這也回答了為什么ThreadLocal可以定義為static, 它只是Map中的Key而已,不同線程的Map副本獲取同一個Key的值完全不會沖突。
類ThreadLocal: 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(); } /** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use * WeakReferences for keys. However, since reference queues are not * used, stale entries are guaranteed to be removed only when * the table starts running out of space. */ static class ThreadLocalMap {...} 類Thread: /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
Thread1 : ThreadLocalMap1 : <ThreadLocal1, String> <ThreadLocal2, Integer>Thread2 : ThreadLocalMap2 : <ThreadLocal1, String> <ThreadLocal2, Integer>
繼續延伸出一個問題: ThreadLocal類本身是線程安全的么?
通過源碼看到不管是get,set還是createMap都沒有做任何的同步或者并發鎖。答案是安全的,因為實現都是基于當前線程的。
在線程池復用的情況下,若ThreaLocal數據沒有被清理掉,會被后面的請求復用然后拿到被你修改過的值!
之前在實現日志上下文LogContext的時候碰到了類似問題:
請求A進入Controller中, 開啟線程A,LogContext中記錄了大量的ThreadLocal中間變量值,在請求響應結束后,請求線程A回歸線程池;
請求B進入Controller中,復用線程A,LogContext會在之前變量值的基礎上繼續添加信息,這樣的日志信息成了疊加的了。
不管是基于自己實現的線程池,還是應用服務器(如Tomcat)的線程池,都需要小心這一點!
標準或者規范做法是在線程變量使用完畢之后,或者finally代碼塊中調用 threadLocalVariable.remove() 移除,以防被其他線程復用。
上述就是小編為大家分享的ThreadLocal的基本定義是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。