單例模式在高併發情形下造成的訪問覆蓋問題

2021-09-02 12:33:50 字數 1871 閱讀 4826

好吧,最近我特麼是跟高併發槓上了

單例模式想必很很常見,而往往單例模式跟static相關。單例模式的初衷是為了在任何條件下我只得到乙個例項,包括類和變數。而往往需要我們用static關鍵字去修飾達到單例的效果。最近高併發接觸得比較多,使用快取就需要用單例。因為你針對某乙個key的快取只可能定義成「乙份」。所以快取類的例項需要用到單例模式。但是在高併發的條件下,控制不好的話,很容易出問題。下面寫個小例子,就能看出是什麼問題了……

@controller

public class testaction catch (interruptedexception e)

new thread(new testthread("count")).start();

}}class testthread implements runnable

@override

public void run()

}

這裡用啟動兩個執行緒testthread模擬「併發」。

而我們再模擬使用到單例模式的情形:

public class test3 else

return list;

}}

其中list是static的全域性變數。這裡用servletcontext的特性模擬了快取的情況。

看看testaction中定義的執行緒testthread,該執行緒被啟動了2次,(模擬併發),並且2次都是傳入同乙個引數(模擬相同條件)"count"。

瀏覽器輸入testaction註解的url,可發現控制台列印如下:

[a, b, c, d]

[a, b, c, d, d]

再次輸入該url,列印如下:

[a, b, c, d, d, d]

[a, b, c, d, d, d, d]

問題已很明顯了,執行緒第一次執行時,集合本來為[a.b.c]被它修改(add("d"))之後,集合被覆蓋為[a,b,c,d]了;同理,第二次輸入url之後,集合又被執行緒第二次執行時覆蓋為[a,b,c,d,d]了·,所以此次在進行add("d")操作之後,集合被覆蓋為[a,b,c,d,d,d]啦,以此類推……

其實這種問題是比較容易被忽視的,併發條件下,你對乙個「公共」的變數(一般是由static修飾),常見場景如快取的操作(這裡是add("d"))修改,會不斷更新【最初】的變數值,【新】的執行緒再次訪問時,得到的已經不是【最初】的值了。這顯然是不對的,我們需要做到對乙個公共變數進行多執行緒訪問時,執行緒與執行緒之間的訪問不彼此影響,即:執行緒不會修改公共的變數值,不影響其他執行緒的訪問。

注意:需要注意這種情況只涉及到執行緒需要對拿到的公共變數修改時,純讀取的話,沒必要注意這個問題。

如何解決呢?我們只需拷貝乙個公共變數的「副本」,即可達到想要的效果:

改變test3的方法如下:

public static listgetlist(string attr) else

listcopylist = new arraylist(list);

return copylist;

}

copylist是公共變數的副本,這樣,當有n個執行緒去訪問公共變數時,得到的是副本,你之後再對該副本進行任何操作,都不會影響公共變數,從而不影響其他執行緒對該公共變數的訪問,確保其他執行緒拿到的都是【最初】的公共變數。

同樣,訪問url,

列印如下:

[a, b, c, d]

**********=

[a, b, c, d]

**********=

再次訪問:

[a, b, c, d]

**********=

[a, b, c, d]

**********=

說明:問題解決。

單例模式併發

在研究單例模式的時候,為了保證單例的懶載入是同步的,我們通常會選擇乙個duoble check的方法來保證只有第一次才new物件。1.雙重檢測同步延遲載入 如下 關於volatile的作用在這裡就是保證在new出物件的那一立馬寫入主存,同時通知其他執行緒的他們的cache是無效的,這樣instanc...

單例模式 併發訪問

一 餓漢式 多執行緒併發,相對安全 class single private static final single s new single public static single getinstance 二 懶漢式 class single private static single s nu...

單例模式 單執行緒和多執行緒併發情況下的物件建立

1.單例項控制 namespace singletonpattern 單程序 單執行緒下獲取例項 public static singleton getinstance 併發環境下的單例物件建立 public static singleton getinstance return instance ...