天天看點

Spring中采用公共變量并發問題解決

由于系統采用springmvc架構,springmvc核心控制器DispatcherServlet 預設為每個controller生成單一執行個體來處理所有使用者請求,是以在這個單一執行個體的controller中,它的XXXService也是一個執行個體處理所有請求, 這樣XXXService的成員變量就被所有請求共享。這樣就會出現并發請求時變量内容被篡改的問題。

那麼出現這種問題如何解決呢?

第一種方式: 既然是全局變量惹的禍,那就将全局變量都程式設計局部變量,通過方法參數來傳遞,但是如果多個方法都需要該參數的話,傳參就相當繁瑣。

第二種方式: jdk提供了java.lang.ThreadLocal,它為多線程并發提供了新思路。 (當使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,是以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本)

ThreadLocal類用來提供線程内部的局部變量。這些變量在多線程環境下通路(通過get或set方法通路)時能保證各個線程裡的變量相對獨立于其他線程内的變量,ThreadLocal執行個體通常來說都是private static類型。

總結:ThreadLocal不是為了解決多線程通路共享變量,而是為每個線程建立一個單獨的變量副本,提供了保持對象的方法和避免參數傳遞的複雜性。

父類ThreadLocal定義:

父類設定對象值:

子類使用:

ThreadLocal的主要應用場景為按線程多執行個體(每個線程對應一個執行個體)的對象的通路,并且這個對象很多地方都要用到。例如:同一個網站登入使用者,每個使用者伺服器會為其開一個線程,每個線程中建立一個ThreadLocal,裡面存使用者基本資訊等,在很多頁面跳轉時,會顯示使用者資訊或者得到使用者的一些資訊等頻繁操作,這樣多線程之間并沒有聯系而且目前線程也可以及時擷取想要的資料。

實作原理:

ThreadLocal可以看做是一個容器,容器裡面存放着屬于目前線程的變量。ThreadLocal類提供了四個對外開放的接口方法,這也是使用者操作ThreadLocal類的基本方法:

(1) void set(Object value)設定目前線程的線程局部變量的值。

(2) public Object get()該方法傳回目前線程所對應的線程局部變量。

(3) public void remove()将目前線程局部變量的值删除,目的是為了減少記憶體的占用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束後,對應該線程的局部變量将自動被垃圾回收,是以顯式調用該方法清除線程的局部變量并不是必須的操作,但它可以加快記憶體回收的速度。

(4) protected Object initialValue()傳回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆寫而設計的。這個方法是一個延遲調用方法,線上程第1次調用get()或set(Object)時才執行,并且僅執行1次,ThreadLocal中的預設實作直接傳回一個null。

可以通過上述的幾個方法實作ThreadLocal中變量的通路,資料設定,初始化以及删除局部變量,那ThreadLocal内部是如何為每一個線程維護變量副本的呢?

其實在ThreadLocal類中有一個靜态内部類ThreadLocalMap(其類似于Map),用鍵值對的形式存儲每一個線程的變量副本,ThreadLocalMap中元素的key為目前ThreadLocal對象,而value對應線程的變量副本,每個線程可能存在多個ThreadLocal。

<a href="http://blog.csdn.net/lhqj1992/article/details/52451136">http://blog.csdn.net/lhqj1992/article/details/52451136</a>