多執行緒問題與double check

2022-01-15 06:20:58 字數 1720 閱讀 7464

在乙個多執行緒程式中,如果共享資源同時被多個執行緒使用,就有可能會造成多執行緒問題,這主要取決於針對該資源的某項操作是否是執行緒安全的。例如,.net中的dictionary就是乙個完全執行緒不安全的資料結構,對於dictionary的插入、刪除都有可能帶來多執行緒問題,這主要是由於dictionary的內部實現結構會頻繁的由於插入、刪除操作而改變長度,這時,如果出現多執行緒問題,程式最可能丟擲陣列越界的exception。特別的,對於webservice來講,每乙個請求都會生成乙個thread/instance,因此就要特別注意多執行緒問題了。

一般地,多執行緒問題常常發生於對於共享資源的同時使用。例如,對於類的成員變數的使用,對於全域性靜態變數的使用,而對於函式內部的區域性變數而言,一般式不會存在多執行緒問題的,因為每個執行緒在呼叫乙個特定的函式時,都會生成乙份函式內部成員變數的副本,執行緒和執行緒之間是互不相干的。

解決多執行緒問題,最常見的方式就是加鎖,使得某一資源在同一時刻只能被乙個執行緒所用,而其他執行緒則必須在被加鎖的**外等待,直到鎖被解除,例如如下c#**所示:

1

lock

(_lock)

2

下面說說double-check。

多執行緒問題也常常和一種lazy-initialize的設計模式聯絡在一起。在這裡就會慢慢引出double-check。lazy-initialize講的是,對於一些特別複雜的物件,讓程式在第一次呼叫它的時候再對它進行初始化,而且保證僅僅初始化一次。

首先想到的設計是這樣的:

1

classa2

13return

_result;14}

15 }

但是這樣有乙個問題。complexclass的構造過程較長的話,當第乙個執行緒還在進行complexclass構造的時候,_result可能是null,也可能指向了乙個尚未初始化完成的物件。這樣,要麼兩個執行緒初始化了兩次complexclass,要麼第二個執行緒會返回乙個指向不完整物件的引用。所以,在這裡需要用到乙個鎖,如下所示:

1

complexclass getresult()29

}10return

_result;

11 }

這樣,雖然多執行緒的問題解決了,但是每一次需要使用result時都會請求鎖,而請求鎖對程式的效能是有很大影響的,因此我們在lock的外面再加一層check:

1

complexclass getresult()211

}12}13

return

_result;

14 }

這樣,對於所有初始化完成後的請求,就都不用請求鎖,而是直接返回_result。

但是還是存在一點問題。對於一些程式語言來說,_result = new complexclass();這句**會使得_result指向乙個部分初始化的物件。也就是說,當執行緒a在初始化complexclass時,執行緒b有可能會判斷_result已經不是null了,而這時其實初始化尚未完成,這時執行緒b就直接返回了乙個部分初始化的物件,會造成程式的崩潰。那麼,這個問題怎麼解決呢?一般的解決方法是在程式內部再加乙個區域性變數(標識變數)做一層緩衝:

1

complexclass getresult()213

}14}15

return

_result;

16 }

這樣,上面的問題就徹底解決了~

多執行緒問題

問題描述 有4個執行緒和1個公共的字元陣列。執行緒1的功能就是向陣列輸出a,執行緒2的功能就是向字元輸出b,執行緒3的功能就是向陣列輸出c,執行緒4的功能就是向陣列輸出d。要求按順序向陣列賦值abcdabcdabcd,abcd的個數由執行緒函式1的引數指定。注 c語言選手可使用windows sdk...

多執行緒問題

程式 是由多個程序組成的。可以理解為靜態的 程序 可以理解為執行中的程式。執行緒 是組成程序的單元,乙個程序中有多個執行緒。我們經常把執行緒看做是程序中的某乙個任務。方式一 繼承乙個thread類 方式二 實現乙個runnable介面 兩種方式相比較,哪個能好點那?一般建議是實現runnable介面...

多執行緒問題

執行緒先達到corepoolsize,達到了去排隊 佇列滿了就去新建執行緒,達到了maxpoolsize 就執行拒絕策略了。所以大家在取queuesize的時候,就要取getthreadpoolexecutor getpoolsize getthreadpoolexecutor getqueue s...