運用volatile建立安全的多執行緒下的單例模式

2021-10-07 07:45:51 字數 2638 閱讀 4064

public

class

singletondemo

public

static singletondemo getinstance()

return instance;

}public

static

void

main

(string[

] args)

}

但是這種單例模式在多執行緒下會出問題。

public

class

singletondemo

public

static singletondemo getinstance()

return instance;

}public

static

void

main

(string[

] args)

, string.

valueof

(i))

.start()

;}}}

public

class

singletondemo

public

synchronized

static singletondemo getinstance()

return instance;

}public

static

void

main

(string[

] args)

, string.

valueof

(i))

.start()

;}}}

這樣雖然可以保證多執行緒下的單例模式,但是為了獲取單例,將整個方法用synchronized鎖住,沒有必要,大大影響多執行緒的效率。

public

class

singletondemo

public

static singletondemo getinstance()

}}}public

static

void

main

(string[

] args)

, string.

valueof

(i))

.start()

;}}}

這樣上鎖,看似沒有什麼問題,但是可能有很小很小很小的機率出問題,分析如下:

原因在於某乙個執行緒執行到第一次檢測,讀取到的instance不為null時,instance的引用物件可能沒有完成初始化。

instance = new singletondemo();可以分為以下3步完成(偽**)

memory = allocate(); //1.分配物件記憶體空間

instance(memory); //2. 初始化物件

instance = memory; //3. 設定instance指向剛分配的記憶體位址,此時instance! =null

步驟2和步驟3不存在資料依賴關係,而且無論重排前還是重排後程式的執行結果在單執行緒中並沒有改變,因此這種重排優化是允許的。

memory = allocate(); //1.分配物件記憶體空間

instance = memory; //3. 設定instance指向剛分配的記憶體位址,此時instance! =null, 但是物件還沒有初始化完成!

instance(memory); //2.初始化物件

但是指令重排只會保證序列語義的執行的一致性(單執行緒), 但並不會關心多執行緒間的語義一致性。

所以當一條執行緒訪問instance不為null時,由於instance例項未必已初始化完成,也就造成了執行緒安全問題。

下面就對上面所說打乙個比方:

步驟1就好比,老師上課時候,說1排1座現在沒有人,我們在1小時候會安排同學「張三」坐到這裡。

步驟2就好比,張三已經辦完入學手續,坐到1排1座。

步驟3就好比,同學們的目光被1排1座吸引,看到了坐在1排1座上的張三。

由於存在指令重排,可能步驟是1-3-2,這就好比老師上課時候,說1排1座現在沒有人,我們在1小時候會安排同學「張三」坐到這裡。但是有些同學反應比較快,立刻看向1排1座,看到了空位置,心裡想到,哦,這就是張三。然後1小時候張三辦完入學手續,來到1排1座,其他同學看向1排1座,看到了真正的張三。

在實際中,就是雖然為物件建立了記憶體位址,但是還沒有建立例項,就拿來用,有可能會得到null。

以上,我們需要在單例模式中,禁止系統自動指令重排來保證例項安全性。

具體**如下:

public

class

singletondemo

public

static singletondemo getinstance()

}}return instance;

}public

static

void

main

(string[

] args)

, string.

valueof

(i))

.start()

;}}}

建立安全組

操作場景 您可以建立安全組並定義安全組中的規則,將vpc中的彈性雲伺服器劃分成不同的安全域,以提公升彈性雲伺服器訪問的安全性。建議您將不同公網訪問策略的彈性雲伺服器劃分到不同的安全組。操作步驟 登入管理控制台。在管理控制台左上角單擊 在系統首頁,選擇 網路 虛擬私有雲 在左側導航樹選擇 訪問控制 安...

建立安全組

操作場景 您可以建立安全組並定義安全組中的規則,將vpc中的彈性雲伺服器劃分成不同的安全域,以提公升彈性雲伺服器訪問的安全性。建議您將不同公網訪問策略的彈性雲伺服器劃分到不同的安全組。操作步驟 登入管理控制台。在管理控制台左上角單擊 在系統首頁,選擇 網路 虛擬私有雲 在左側導航樹選擇 訪問控制 安...

django 建立安全索引

上篇記錄使用 concurrently 命令列執行不鎖表索引,對於django,如何執行呢?這裡記錄一種方法,修改django遷移檔案。在執行完遷移後,為了方便找到該遷移檔案,可以採用指定命名遷移 1 migrations 0002 add index separate database and s...