最近進入項目組開發,偶爾翻閱別人代碼時,看到以下注釋。 html
剛看到時徹底不解,不知道其爲何這麼說。當同事跟我解釋緣由,豁然開朗。細想,咱們在工做使用中,若是不注意很容易就忽略這個問題。 在解釋這個問題先,咱們先來查看 ThreadLocal。java
ThreadLocal 提供線程局部(thread-local)變量,爲每一個線程建立單獨的變量副本,這樣在多線程環境的下,因爲每一個線程都有單獨的變量,不會由於變量共享致使的併發問題。固然相關問題我能夠們使用同步機制解決該問題。git
同步機制跟 ThreadLocal 區別github
使用同步機制,多線程環境共享同一變量,這須要咱們在使用時顯示加鎖,保證變量在同一時間只有一個線程能使用,至關於採用時間策略換取線程安全。web
使用 ThreadLocal,每一個線程擁有本身獨立變量副本,至關於採用空間策略換取線程安全。spring
咱們從代碼查看下兩種方式的區別。如今假如咱們須要當前一個時間工具類,以下:apache
private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String getDateStr(Date date) {
return format.format(date);
}
複製代碼
查看上面 Demo,咱們很容易能夠看出上面方法因爲是 SimpleDateFormat 不是線程安全,從而致使 getDateStr 方法非線程安全。安全
如今咱們使用同步對其改造。多線程
private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static synchronized String getDateStrSync(Date date) {
return format.format(date);
}
複製代碼
這樣使用顯示加鎖,避免多線程環境下線程安全。可是這種方式可能在高併發狀況影響效率。併發
下面使用 ThreadLocal 對其改造。
private final static ThreadLocal<SimpleDateFormat> formatLocal = new ThreadLocal<SimpleDateFormat>() {
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static String getDateByLocal(Date date){
return formatLocal.get().format(date);
}
複製代碼
使用 ThreadLocal,將共享變量變成獨享變量,保證線程安全。可是該種方案增長建立對象的開銷。
綜上,如何選擇上述兩種方式,須要結合當前業務方式選擇。
講完 ThreadLocal,咱們來看下的 dubbo 的線程模型。
dubbo 默認採用單一長鏈接加線程池方式處理調用。
默認採起 Dispatcher=all 的分發策略,全部消息都派發到線程池,包括請求,響應,鏈接事件,斷開事件,心跳等。線程池在缺省配置爲固定大小線程池,啓動時創建線程,不關閉,一直持有。默認爲100個線程。
在 Dubbo 中使用 ThreadLocal ,若是採用默認的設置,每次 Dubbo 調用結束,Dubbo 處理響應線程並不會被銷燬, 而是歸還到線程池中。而從 ThreadLocal 源碼能夠看出,每次咱們設置的值其實會存在位於 Thread 中 ThreadLocalMap 變量中。
這就致使,下次若是 Dubbo 處理響應剛好繼續使用到這個線程,該線程就能調用到上次響應中設置在 ThreadLocal 設置的值。這就引發內存泄露,可能還會致使業務上異常。其實並不止在 Dubbo 中,該案例還會發生在 web項目中,只要相關使用線程池的,都有可能發生。
使用 Threadlocal,咱們須要注意幾點:
若是以爲好的話,請幫做者點個讚唄~ 謝謝
喜歡本文的讀者們,歡迎長按關注訂閱號程序通事~讓我與你分享程序那些事。