多執行緒下的集合安全

2022-09-13 12:27:11 字數 4719 閱讀 1469

在多執行緒內使用集合,如果未對集合做任何安全處理,就非常容易出現系統崩潰或各種錯誤。最近的專案裡,使用的是socket通訊後再改變了某個集合,結果導致系統直接崩潰,且無任何錯誤系統彈出。

經排查,發現問題是執行某集合後,系統就會在一定時間內退出,最後發現是使用的乙個字典集合出了問題。稍微思考後,就認定了是執行緒安全問題。因為此集合在其它幾個地方都有執行緒做迴圈讀取。

下面是我模擬的乙個示例,沒有進行任何的安全處理:

1

class

program214

public

static

void

addmethod()

1521}22

public

static

void

readmethod()

2333}34

}35}36

public

class

mycollection

3746

else

4750}51

52public

void remove(string

key)

5358

}59 }

在上面的示例中,建立了乙個dictionary字典對像,程式執行時,輸出了下面的錯誤:

程式執行時,輸出了上面的錯誤,僅僅輸出了一行結果

這次測試有明顯示的錯誤提示,集合已修改;可能無法執行列舉操作。

唉,真是乙個常見的問題,在foreach的時侯又修改集合,就一定會出現問題了,因為foreach是唯讀的,在進行遍歷時不可以對集合進行任何修改。

看到這裡,我們會想到,如果使用for迴圈進行逆向獲取,也許可以解決此問題。

非常可惜,字典對像沒有使用索引號獲取的辦法,下面的****(

type

內部結構

支援索引

記憶體占用

隨機插入的速度(毫秒)

順序插入的速度(毫秒)

根據鍵獲取元素的速度(毫秒)

未排序字典

dictionary

雜湊表否

2230

3020

hashtable

雜湊表否

3850

5030

listdictionary鍊錶否

3650000

50000

50000

ordereddictionary

雜湊表 +陣列是59

7070

40排序字典

sorteddictionary

紅黑樹否

20130

100120

sortedlist

2xarray是20

3300

3040

sortlist

2xarray是27

4500

100180

從時間複雜度來講,從字典中通過鍵獲取值所耗費的時間分別如下:

這可如何是好,只能改為可排序的對像?然後使用for解決?

我突然想到,是否可以在迴圈時縮短foreach,來解決此問題呢?

想到可以在迴圈時先copy乙份副本,然後再進行迴圈操作,編寫**,查詢copy的方法。真是無奈,沒有提供任何的copy方法。唉!看來人都是用來被逼的,先改個物件吧:

把dictionary修改成了hashtable對像(也沒有索引排序)。**如下:

1

class

program214

public

static

void

addmethod()

1521}22

public

static

void

readmethod()

2333}34

}35}36

public

class

mycollection

3747

else

4851}52

53public

void remove(string

key)

5459

}60 }

**一如即往的報錯,錯誤資訊一樣。

使用copy法試試

1

class

program214

public

static

void

addmethod()

1521}22

public

static

void

readmethod()

2336}37

}38}39

public

class

mycollection

4050

else

5154}55

56public

void remove(string

key)

5762

}63 }

輸出結果如下:

以上結果輸出

寫到這裡,我自己都有些模糊了。這文章和執行緒安全有毛關係。

根據msdn執行緒安全解釋如下:

hashtable

從頭到尾對乙個集合進行列舉本質上並不是乙個執行緒安全的過程。即使乙個集合已進行同步,其他執行緒仍可以修改該集合,這將導致列舉數引發異常。若要在列舉過程中保證執行緒安全,可以在整個列舉過程中鎖定集合,或者捕捉由於其他執行緒進行的更改而引發的異常。

經過我們模擬,沒有發現多執行緒下錯誤,但為安全起見,我們在使用時,最好根據msdn所述,在對執行緒操作時加上安全鎖處理,這裡我們不需自己定義鎖物件,因為微軟直接提供了syncroot進行安全鎖處理。

修改後的**如下:

時間損耗

1

public

static

void

readmethod()

213 console.writeline("

\r\n******************************===\r\n");

14foreach (dictionaryentry item in

tempht)

1520

if (tempht != null && tempht.count == 20)21

24}25 stopwatch.stop(); //

停止監視

26 timespan timespan = stopwatch.elapsed; //

獲取當前例項測量得出的總時間

27 console.writeline("

全部加滿用時:

好了,多執行緒安全問題就說到這裡,總結來說就是注意鎖在多執行緒中的應用。

如有此文章內存在問題,還請多多指正。

Java多執行緒理解 執行緒安全的集合物件

1 概念介紹 2 執行緒安全的集合物件 3 測試 3 原因分析 4 執行緒安全的集合並不安全 分析以下場景 synchronized map return value 由於執行緒安全的集合物件是基於單個方法的同步,所以即使map是執行緒安全的,也會產生不同步現象。在非單個方法的場景下,我們仍然需要使...

(多執行緒)多執行緒的併發安全

多執行緒併發操作同乙個資源 同步鎖 多執行緒操作的鎖必須唯一 必須搞清楚 哪些 需要同步?那些在操作共享資源的 只要包含非讀的操作,或者根據共享資源進行條件判斷的,就需要同步!同步 塊解決 package com.gc.thread 多執行緒操作共享資源 併發 執行緒安全問題 同步 鎖 相對而言效能...

執行緒安全的集合

集合大概有4種型別 list set queue map其中vector hashtable properties是執行緒安全的。其中arraylist linkedlist hashset treeset hashmap treemap等都是執行緒不安全的。執行緒不安全是指 當多個執行緒訪問同乙個...