java 线程变量put_Java线程(篇外篇):线程本地变量ThreadLocal
首先說明ThreadLocal存放的值是線程內共享的,線程間互斥的,主要用于線程內共享一些數據,避免通過參數來傳遞,這樣處理后,能夠優雅的解決一些實際問題,比如hibernate中的OpenSessionInView,就是使用ThreadLocal保存Session對象,還有我們經常用ThreadLocal存放Connection,代碼如:
/**
*?數據庫連接管理類
*?@author?爽
*
*/
public?class?ConnectionManager?{
/**?線程內共享Connection,ThreadLocal通常是全局的,支持泛型?*/
private?static?ThreadLocal?threadLocal?=?new?ThreadLocal();
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有四個方法,分別為:
initialValue
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方法:
/**
*?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方法:
/**
*?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()方法。
(完)
總結
以上是生活随笔為你收集整理的java 线程变量put_Java线程(篇外篇):线程本地变量ThreadLocal的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php 文件指定位置添加内容,C++_V
- 下一篇: 17福师《计算机应用基础,福师17春秋学