ThreadLocal使用注意

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();
                }
            }
複製代碼
  • 採用匿名內部類賦初始值
  • 顯式調用get()、set()
  • 在不用的時候顯式地remove()掉
  • 對於顯示的remove特別重要,由於這樣能夠避免entry不被GC的狀況
  • 若是爲了不ThreadLocal被GC,能夠增強ThreadLocal的引用,將其聲明成private static
相關文章
相關標籤/搜索