單例模式的線程安全性

普通的單例模式是線程不安全的,驗證方法如下:

```

sealed class Singleton1

? ? {

? ? ? ? private Singleton1()

? ? ? ? {

? ? ? ? }

? ? ? ? private static Singleton1 instance = null;

? ? ? ? public static Singleton1 Instance

? ? ? ? {

? ? ? ? ? ? get

? ? ? ? ? ? {

? ? ? ? ? ? ? ? if (instance == null)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? Console.WriteLine("Cup");

? ? ? ? ? ? ? ? ? ? instance = new Singleton1();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return instance;

? ? ? ? ? ? }

? ? ? ? }

? ? }

class Program

? ? {

? ? ? ? static void Main(string[] args)

? ? ? ? {

? ? ? ? ? ? Singleton1 st1 = null;

? ? ? ? ? ? Singleton1 st2 = null;

? ? ? ? ? ? while (true)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Thread t1 = new Thread(() =>

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? st1 = Singleton1.Instance;

? ? ? ? ? ? ? ? });

? ? ? ? ? ? ? ? Thread t2 = new Thread(() =>

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? st2 = Singleton1.Instance;

? ? ? ? ? ? ? ? });

? ? ? ? ? ? ? ? t1.Start();

? ? ? ? ? ? ? ? t2.Start();

? ? ? ? ? ? ? ? Thread.Sleep(100);

? ? ? ? ? ? }

? ? ? ? }

? ? }

```

如上所示,打印的結(jié)果有很大概率出現(xiàn)兩次"Cup",說明兩個線程都創(chuàng)建了新的對象,單例被打破了。

改進方式:加鎖

```

sealed class Singleton1

? ? {

? ? ? ? private Singleton1()

? ? ? ? {

? ? ? ? }

? ? ? ? private static readonly object syncObj = new object();

? ? ? ? private static Singleton1 instance = null;

? ? ? ? public static Singleton1 Instance

? ? ? ? {

? ? ? ? ? ? get

? ? ? ? ? ? {

? ? ? ? ? ? ? ? lock (syncObj)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? if (instance == null)

? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? Console.WriteLine("Cup");

? ? ? ? ? ? ? ? ? ? ? ? instance = new Singleton1();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return instance;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? public void Clear()

? ? ? ? {

? ? ? ? ? ? instance = null;

? ? ? ? }

? ? }

```

運行結(jié)果只有一個"Cup",程序在進入代碼段時首先判斷有沒有加鎖,如果沒有就加鎖,另一個線程判斷代碼已經(jīng)有鎖了,就直接返回,從而保證了單例的唯一性。

缺點:判斷鎖狀態(tài)和嘗試加鎖操作比較消耗性能

改進:鎖前判斷:

```

public static Singleton1 Instance

? ? ? ? {

? ? ? ? ? ? get

? ? ? ? ? ? {

? ? ? ? ? ? ? ? if (instance == null)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? lock (syncObj)

? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? if (instance == null)

? ? ? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? ? ? Console.WriteLine("Cup");

? ? ? ? ? ? ? ? ? ? ? ? ? ? instance = new Singleton1();

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return instance;

? ? ? ? ? ? }

? ? ? ? }

```

如此,就只有第一次試圖創(chuàng)建實例時要加鎖

有沒有不用鎖的辦法呢,也有:

```

sealed class Singleton1

? ? {

? ? ? ? private Singleton1()

? ? ? ? {

? ? ? ? }

? ? ? ? private static Singleton1 instance = new Singleton1();

? ? ? ? public static Singleton1 Instance

? ? ? ? {

? ? ? ? ? ? get

? ? ? ? ? ? {

? ? ? ? ? ? ? ? if (instance != null)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? return instance;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? return null;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? }

```

C#在調(diào)用靜態(tài)構(gòu)造函數(shù)時初始化靜態(tài)變量,運行時能夠確保只調(diào)用一次靜態(tài)構(gòu)造函數(shù)。但這種機制不確定在其他語言中也存在

如果局限于C#中,還有更優(yōu)化的方法:

```

sealed class Singleton1

? ? {

? ? ? ? private Singleton1()

? ? ? ? {

? ? ? ? }

? ? ? ? public static Singleton1 Instance

? ? ? ? {

? ? ? ? ? ? get

? ? ? ? ? ? {

? ? ? ? ? ? ? ? return Nested.instance;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? class Nested

? ? ? ? {

? ? ? ? ? ? static Nested()

? ? ? ? ? ? {

? ? ? ? ? ? }

? ? ? ? ? ? internal static readonly Singleton1 instance = new Singleton1();

? ? ? ? }

? ? }

```

將創(chuàng)建實例的時機局限在獲取Instance時。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 對象的創(chuàng)建與銷毀 Item 1: 使用static工廠方法,而不是構(gòu)造函數(shù)創(chuàng)建對象:僅僅是創(chuàng)建對象的方法,并非Fa...
    孫小磊閱讀 2,184評論 0 3
  • 設(shè)計模式分類 總體來說設(shè)計模式分為三大類:創(chuàng)建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原...
    lifeline丿毅閱讀 1,348評論 0 2
  • 前言 本文主要參考 那些年,我們一起寫過的“單例模式”。 何為單例模式? 顧名思義,單例模式就是保證一個類僅有一個...
    tandeneck閱讀 2,627評論 1 8
  • 姓名夏鋼,無錫夏利達公司 【日精進打卡第37天】 【知~學(xué)習(xí)】 《六項精進》2遍共2遍 《大學(xué)》1遍共1遍 【經(jīng)典...
    Atun0219閱讀 249評論 0 0
  • 他,不是人,不是物,但他十分寶貴,讓我們時時刻刻珍惜他。他就是時間,我們摸不到,看不著,也抓不住。 從古至今,許許...
    Mr白茶與鹿閱讀 763評論 1 4

友情鏈接更多精彩內(nèi)容