【多執行緒】ThreadLocal原理
使用
ThreadLocalthreadLocalA= new ThreadLocal (); threadLocalA.set(new String("A")); String str = threadLocalA.get();
原理
在每個執行緒的內部有個資料結構為Map的threadLocals變數,以
當使用set()方法時:
獲取到當前執行緒的threadLocals,型別為Map
將這值放到這個Map結構的變數中,key為ThreadLocal物件,value為所有存放的值
當使用get()方法時:
獲取到當前執行緒的threadLocals,型別為Map。
以ThreadLocal物件為Map的key獲取到它的value值。
因為ThreadLocal物件作為Map的key,所以一個ThreadLocal物件只能存放一個值,當存放多個時,會將新值覆蓋舊值。
原始碼
資料結構:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);//當前執行緒為入參,獲取當前執行緒的threadLocals變數 if (map != null) //入參為this,也就是說key為ThreadLocal物件 map.set(this, value); else createMap(t, value); } public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);//當前執行緒為入參,獲取當前執行緒的threadLocals if (map != null) { //入參為this,也就是說key為ThreadLocal ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } ThreadLocalMap getMap(Thread t) { return t.threadLocals;//threadLocals為執行緒的變數 } private Entry getEntry(ThreadLocal> key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e);//避免記憶體洩漏,下文有提。 }
記憶體洩漏
ThreadLocalMap結構如下:
static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference> { Object value; Entry(ThreadLocal> k, Object v) { super(k); //key,這個是一個弱引用,如果沒有強引用來引用key(也就是ThreadLocal),則key會被回收,形成了key為null的Entry。 value = v; } } private Entry[] table; }
threadLocals變數是線上程內部的,故沒有多個執行緒去訪問它,所以不存線上程不安全的說法,同時只要執行緒被回收了就不會存在記憶體洩漏。
ThreadLocal物件被回收時(key為null),沒有辦法獲取到value,而執行緒又不會被回收時則value一直佔用空間導致記憶體洩漏。執行緒不會被回收的常見場景是執行緒池。
JDK在此做了一個最佳化,在呼叫get(),set(),remove()方法會做額外處理來清理ThreadLocalMap中key為null的value,以減少記憶體洩漏的影響。但是如果key未使用弱引用,即使ThreadLocal被回收了,key也不為null,也就是說是沒法判斷哪個value需要回收的,最終造成記憶體洩漏。所以此處的弱引用key是記憶體洩漏的一個最佳化處理方式。
使用場景
在實際專案中,可以用來減少同一個執行緒內多個函式或者元件之間一些公共變數的傳遞的複雜度,因為servlet是單例多執行緒的,每個請求執行的操作都是同一個執行緒中。比如:可以用ThreadLocal來存每一次請求使用者的資訊,定義了一個類UserContextHolder
public class UserContextHolder{ private static ThreadLocaluserContextHolder = new ThreadLocal(); public static setUser(User user){ userContextHolder.set(user); } public static User getUser(){ return userContextHolder.get(); } public static void remove(){ return userContextHolder.remove(); } }
當使用者每次請求進來時,在攔截器中獲取使用者資訊呼叫UserContextHolder.setUser()將其放到userContext中,無論在哪我們只要呼叫UserContextHolder.getUser()可以很輕鬆的獲取到使用者的資訊,而不用在函式呼叫時一層一層的傳遞。同時在攔截器結束時呼叫UserContextHolder.remove()移除掉即可。
作者:eejron
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2249/viewspace-2802539/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java多執行緒與併發之ThreadLocalJava執行緒thread
- java多執行緒原理Java執行緒
- 多執行緒:原理分析整理執行緒
- java多執行緒:執行緒池原理、阻塞佇列Java執行緒佇列
- 執行緒安全處理之Threadlocal執行緒thread
- 執行緒的私有領地 ThreadLocal執行緒thread
- 多執行緒和多執行緒同步執行緒
- 多執行緒下載原理解析執行緒
- 多執行緒斷點下載原理執行緒斷點
- 多執行緒--執行緒管理執行緒
- 執行緒與多執行緒執行緒
- 多執行緒【執行緒池】執行緒
- 多執行緒系列(十八) -AQS原理淺析執行緒AQS
- Java併發/多執行緒-CAS原理分析Java執行緒
- Java多執行緒-執行緒中止Java執行緒
- 多執行緒之初識執行緒執行緒
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- 多執行緒系列(1),多執行緒基礎執行緒
- a、多執行緒執行緒
- 多執行緒系列之 執行緒安全執行緒
- iOS 多執行緒之執行緒安全iOS執行緒
- Java多執行緒之執行緒中止Java執行緒
- Android多執行緒之執行緒池Android執行緒
- Java多執行緒-執行緒狀態Java執行緒
- Java多執行緒-執行緒通訊Java執行緒
- kuangshenshuo-多執行緒-執行緒池執行緒
- java 多執行緒守護執行緒Java執行緒
- Java多執行緒(2)執行緒鎖Java執行緒
- 多執行緒之手撕執行緒池執行緒
- java多執行緒9:執行緒池Java執行緒
- 【java多執行緒】(二)執行緒停止Java執行緒
- 執行緒以及多執行緒,多程式的選擇執行緒
- 多執行緒學習一(多執行緒基礎)執行緒
- Java多執行緒(一)多執行緒入門篇Java執行緒
- Java執行緒池二:執行緒池原理Java執行緒
- 執行緒本地ThreadLocal的介紹與使用!執行緒thread
- 多執行緒,多程式執行緒
- 【多執行緒總結(二)-執行緒安全與執行緒同步】執行緒