ThreadLocal的出現是一種空間換時間的思想的運用,是爲了多線程環境下單線程內變量共享的問題。它的原理就是每一個線程經過ThreadLocal.ThreadLocalMap,保存當前線程中全部ThreadLocal變量引用的key和值。至關於每一個線程有各自的變量副本,線程內共享這個變量數據,線程間互不影響。java
ThreadLocal有它本身的使用場景,好比Spring中用它瞭解決Session、Connection等多線程併發訪問問題,但不能它不能用來代替爲了解決多線程安全問題的同步關鍵字,由於它實際上沒有多線程間的變量共享,而線程安全問題是指多線程間變量共享,且共享變量可修改,進而可能會出現多線程併發修改共享變量的問題,這種須要經過同步手段解決。安全
ThreadLocal變量通常要聲名成static類型,即當前線程中只有一個T類型變量的實例,線程內可共享該實例數據且不會出問題,如將其聲名成非static,則一個線程內就存儲多個T類型變量的實例,有點存儲空間的浪費,通常不多有這樣的應用場景。另外根據實際狀況,ThreadLocal變量聲名時也多加上private final關鍵詞代表它時類內私有、引用不可修改。多線程
在線程池環境下,因爲線程是一直運行且複用的,使用ThreadLocal時會出現這個任務看到上個任務ThreadLocal變量值以及內存泄露等問題,解決方法就是在當前任務執行完後將ThreadLocal變量remove或設置爲初始值,相似在Struts2 框架中Filter裏的處理方法。併發
雖然ThreadLocal的get,set方法能夠清除ThreadLocalMap中key爲null的value,可是get,set方法在內存泄露後並不會必然調用,因此爲了防止此類狀況的出現,咱們有兩種手段。框架
一、使用完線程共享變量後,顯示調用ThreadLocalMap.remove方法清除線程共享變量;this
二、JDK建議ThreadLocal定義爲private static,這樣ThreadLocal的弱引用問題則不存在了。google
最佳實踐的方法參見google guava eventbus中對於ThreadLocal的使用spa
private final ThreadLocal<Boolean> dispatching;
this.dispatching = new ThreadLocal() {
protected Boolean initialValue() {
return Boolean.valueOf(false);
}
}
if(!((Boolean)this.dispatching.get()).booleanValue()) {
this.dispatching.set(Boolean.valueOf(true));
Dispatcher.PerThreadQueuedDispatcher.Event nextEvent;
try {
while((nextEvent = (Dispatcher.PerThreadQueuedDispatcher.Event)queueForThread.poll()) != null) {
while(nextEvent.subscribers.hasNext()) {
((Subscriber)nextEvent.subscribers.next()).dispatchEvent(nextEvent.event);
}
}
} finally {
this.dispatching.remove();
this.queue.remove();
}
}
複製代碼