著名的雙檢鎖技術

2022-02-12 17:08:54 字數 1707 閱讀 8068

最近公司的專案中發現乙個編譯優化導致的bug。同事敘述為「

在cpu

開啟out-of-order execution

優化時,是有

bug的」。針對這個問題,比較好的優化方法如下:

private static jobmanager self;

private static object asyncobj = new object();

public static jobmanager instance}}

return self;}}

這裡需要解釋一下:

self = new jobmanager()

這句你的本意是為 jobmanager 分配記憶體,呼叫構造器初始化字段,再將引用賦給 self ,即發布出來讓其他執行緒可見。但是,那只是你一廂情願的想法,編譯器可能這樣做:為jobmanager 分配記憶體,將引用發布到(賦給)self,再呼叫構造器。然而,如果在將引用發布給 self 之後,呼叫構造器之前,另乙個執行緒發現 self 不為 null,便開始使用jobmanager物件,這時會發生什麼?這個時候物件的構造器還沒有執行結束!這是乙個很難追蹤的bug。

從雙檢鎖技術的角度來看,使用interlocked.exchange確實是最好的解決方案。但有兩個問題,它該如何解決?

1.速度是否夠快?

2.如果乙個執行緒池執行緒在monitor的執行緒同步構造上阻塞,執行緒池會建立另乙個執行緒來保持cpu的「飽和」,而建立乙個新執行緒的代價是很昂貴的,我們該如何避免這樣的情況?

試著跳出「lock+2次if」的框子,我們可以使用interlocked.compareexchange來解決上面的問題。下面是乙個示例:

internal sealed class mysingleton

}

雖然多個執行緒同時呼叫getmysingleton,會建立2個或者更多的mysingleton物件,但沒有被s_value引用的臨時物件會在以後被垃圾**。大多數應用程式很少會發生同時呼叫getmysingleton的情況,所以不太可能出現建立多個mysingleton物件的情況。上述**帶來優勢是很明顯的,首先,它的速度是非常快,其次,它永不阻塞執行緒。這就解決了前面在雙檢鎖技術中提出的問題。

另外,在.net 4.0中提供了2個型別封裝上述兩種模式(雙檢鎖技術、使用interlocked.compareexchange技術):

泛型system.lazy類和system.threading.lazyinitializer類。下面是2個示例:

public static void main()

輸出結果:

輸出結果:

其中列舉lazythreadsafetymode解釋如下:

public enum lazythreadsafetymode

單例模式的雙檢鎖的隱患和優化

摘錄加總結 1 傳統的單例模式的雙檢鎖 public class singleton return sinstance private singleton 雙檢鎖的設定可以避免在1和2位置處,在併發時假如a執行緒和b執行緒都進入了1位置,但是a獲取到了鎖,new了物件之後,b獲取到鎖之後又重複new...

mysql的技術要點 Mysql 鎖技術要點

myisam和innodb的區別 mysql預設採用的是myisam。myisam不支援事務,而innodb支援。innodb的autocommit預設是開啟的,即每條sql語句會預設被封裝成乙個事務,自動提交,這樣會影響速度,所以最好是把多條sql語句顯示放在begin和commit之間,組成乙個...

雙快門鎖教程 雙快功能的鎖體的製作方法

本發明屬於一種雙快功能的鎖體。背景技術 我們知道,不管是機械式鎖體,還是電子式鎖體,往往都設有斜舌元件 方舌元件 天地銷 聯動板等,人們在門內 外操作執手或鑰匙來斜舌元件 方舌元件推出去鎖門或拉回來縮回到殼體內來開門的同時,通過聯動板來將天地銷推出去鎖門或拉回到殼體內來開門。另外,人們在房內還可以旋...