首先說明ThreadLocal存放的值是線程內共享的,線程間互斥的,主要用于線程內共享一些數據,避免通過參數來傳遞,這樣處理后,能夠優雅的解決一些實際問題,比如hibernate中的OpensessionInView,就是使用ThreadLocal保存Session對象,還有我們經常用ThreadLocal存放Connection,代碼如:
[java] view plain copy PRint?/** * 數據庫連接管理類 * @author 爽 * */ public class ConnectionManager { /** 線程內共享Connection,ThreadLocal通常是全局的,支持泛型 */ private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>(); public static Connection getCurrConnection() { // 獲取當前線程內共享的Connection Connection conn = threadLocal.get(); try { // 判斷連接是否可用 if(conn == null || conn.isClosed()) { // 創建新的Connection賦值給conn(略) // 保存Connection threadLocal.set(conn); } } catch (SQLException e) { // 異常處理 } return conn; } /** * 關閉當前數據庫連接 */ public static void close() { // 獲取當前線程內共享的Connection Connection conn = threadLocal.get(); try { // 判斷是否已經關閉 if(conn != null && !conn.isClosed()) { // 關閉資源 conn.close(); // 移除Connection threadLocal.remove(); conn = null; } } catch (SQLException e) { // 異常處理 } } }這樣處理的好處:
統一管理Connection;不需要顯示傳參Connection,代碼更優雅;降低耦合性。ThreadLocal有四個方法,分別為:
protected T initialValue()返回此線程局部變量的當前線程的初始值。最多在每次訪問線程來獲得每個線程局部變量時調用此方法一次,即線程第一次使用get()
方法訪問變量的時候。如果線程先于 get 方法調用set(T)
方法,則不會在線程中再調用 initialValue 方法。該實現只返回 null;如果程序員希望將線程局部變量初始化為 null 以外的某個值,則必須為 ThreadLocal創建子類,并重寫此方法。通常,將使用匿名內部類。initialValue 的典型實現將調用一個適當的構造方法,并返回新構造的對象。
返回:返回此線程局部變量的初始值get
public T get()返回此線程局部變量的當前線程副本中的值。如果這是線程第一次調用該方法,則創建并初始化此副本。返回:此線程局部變量的當前線程的值set
public void set(T value)將此線程局部變量的當前線程副本中的值設置為指定值。許多應用程序不需要這項功能,它們只依賴于initialValue()
方法來設置線程局部變量的值。參數:value
- 存儲在此線程局部變量的當前線程副本中的值。remove
public void remove()移除此線程局部變量的值。這可能有助于減少線程局部變量的存儲需求。如果再次訪問此線程局部變量,那么在默認情況下它將擁有其 initialValue。很多人對ThreadLocal存在一定的誤解,說ThreadLocal中有一個全局的Map,set時執行map.put(Thread.currentThread(), value),get和remove時也同理,但SUN的大師們是否是如此實現的,我們只能去看源碼了。
set方法:
[java] view plain copy print?/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */ public void set(T value) { // 獲取當前線程對象 Thread t = Thread.currentThread(); // 獲取當前線程本地變量Map ThreadLocalMap map = getMap(t); // map不為空 if (map != null) // 存值 map.set(this, value); else // 創建一個當前線程本地變量Map createMap(t, value); } /** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { // 獲取當前線程的本地變量Map return t.threadLocals; }這里注意,ThreadLocal中是有一個Map,但這個Map不是我們平時使用的Map,而是ThreadLocalMap,ThreadLocalMap是ThreadLocal的一個內部類,不對外使用的。當使用ThreadLocal存值時,首先是獲取到當前線程對象,然后獲取到當前線程本地變量Map,最后將當前使用的ThreadLocal和傳入的值放到Map中,也就是說ThreadLocalMap中存的值是[ThreadLocal對象, 存放的值],這樣做的好處是,每個線程都對應一個本地變量的Map,所以一個線程可以存在多個線程本地變量。
get方法:
[java] view plain copy print?/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ 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(); } 有了之前set方法的分析,get方法也同理,需要說明的是,如果沒有進行過set操作,那從ThreadLocalMap中拿到的值就是null,這時get方法會返回初始值,也就是調用initialValue()方法,ThreadLocal中這個方法默認返回null。當我們有需要第一次get時就能得到一個值時,可以繼承ThreadLocal,并且覆蓋initialValue()方法。(完)
本文來自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/15732053
新聞熱點
疑難解答