ThreadLocal本地線程變數的理解,threadlocal變數
一般的Web應用劃分為展現層、服務層和持久層三個層次,在不同的層中編寫對應的邏輯,下層通過介面向上層開放功能調用。在一般情況下,從接收請求到返迴響應所經過的所有程式調用都同屬於一個線程。 也就是說,同一線程貫通N層,不同的線程可能由於參數等不同會對程式中的某些變數進行修改,但是又要防止修改後的值對其它線程產生影響,因為不同的線程可以同時運行滴,這就需要我們解決對某些線程共用的變數的存取違規問題。ThreadLocal本地線程變數就是一種解決方式,它通過將程式中不安全的變數封裝進ThreadLocal中,這相當於為每一個線程提供一個獨立的變數副本(其實是不同的對象),線程修改變數的值對其它線程來說沒影響了,因為其它線程有自己的一個副本資訊。 代碼理解:
1 // 藉助ThreadLocal對象每個線程只建立一個執行個體 2 public static final String dateFormat="yyyy-MM-dd"; 3 4 private static final ThreadLocal<DateFormat> dfThreadLocal=new ThreadLocal<DateFormat>(){ 5 @Override 6 protected DateFormat initialValue() { 7 return new SimpleDateFormat(dateFormat); 8 } 9 };10 11 public static String dateToString(Date date){12 return dfThreadLocal.get().format(date);13 }
對於每個線程,都有一個類似於Map的東西ThreadLocalMap(ThreadLocal的靜態類 ),那它裡面儲存了什麼東東呢,肯定是key-value啊,key就是上面代碼中的共用靜態變數 dfThreadLocal,value就是DateFormat執行個體了,即new SimpleDateFormat(dateFormat)這個東東。那接下來,線上程內我要如何去擷取這個值呢,就是靠dfThreadLocal.get()實現滴,方法源碼如下:
1 ThreadLocal .ThreadLocalMap inheritableThreadLocals = null ; 2 3 public T get () { 4 Thread t = Thread.currentThread (); 5 ThreadLocalMap map = getMap(t ); 6 if ( map != null) { 7 ThreadLocalMap.Entry e = map.getEntry (this); 8 if ( e != null) 9 return ( T)e .value;10 }11 return setInitialValue ();12 }13 14 ThreadLocalMap getMap (Thread t) {15 return t .inheritableThreadLocals;16 } 可以很明顯的看出,
首先根據Thread.currentThread ()擷取到inheritableThreadLocals(即ThreadLocalMap,他是Thread的一個變數),然後將this(即最上面代碼的dfThreadLocal對象)作為key(或索引)擷取到真正的值T(就是SimpleDateFormat對象)啊,至此應該比較清楚了。 為什麼不同的線程有各自的值,因為
不同的線程--->不同的ThreadLocalMap對象(線程的變數)--->通過相同的key(如果有被static修飾)擷取到不同的value值。 備忘:一般都被static修飾,因為可以避免在一個線程內可能發生的重複建立TSO(Thread Specific Object,即ThreadLocal所關聯的對象),被statis修飾了,同一線程key也肯定一樣,value也肯定只有一份了。 一個ThreadLocal執行個體關聯當前線程的一個TSO對象,如果把ThreadLocal聲明為執行個體變數,那麼每建立一個類執行個體就會導致一個TSO執行個體誕生,這肯定沒有這個必要滴。
更多文章請見我的個人部落格:
http://www.acanblog.com