關於用於靜態變量實現singleton的多線程互斥的一點疑問

都知道singleton模式的線程安全方式有兩種,一種是在GetInstance方法定義上加上synchronized的鎖. 另一種方式是申明成static類型的變量.
我一直有一個疑問.net如何保證static類型是線程安全(實例化變量的操作時間很長,如何保證線程安全)? 我做了如下實驗,的確是線程安全的.

[Form1.cs文件(對話框上僅一個按鈕)]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread1 = new Thread(new ThreadStart(ShowBaseSalary));
            Thread thread2 = new Thread(new ThreadStart(ShowBonusAndSalary));
            thread1.Start();           
            thread2.Start();           
           
        }

        private void ShowBaseSalary()
        {
            MessageBox.Show(Test.GetBaseSalary());
        }

        private void ShowBonusAndSalary()
        {
            MessageBox.Show(Test.GetBonusAndSalary(500));
        }
    }


    class Test
    {
        private static Employee employee = new Employee(29);    //實例化變量的時間可能很長,如何保證線程安全(線程1實例過程中,線程1有可能執行到該代碼嗎?)??
        private int m = 0;

        public static string GetBaseSalary()
        {
            return employee.GetBaseSalary();
        }

        public static string GetBonusAndSalary(int nBonus)
        {
           return employee.GetBonusAndSalary(nBonus);
        }

     
    
    }

 

 

[Employee.cs]

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication2
{
    class Employee
    {

        private const int SALARYLEVEL = 15;  //工資基數

        private int _baseSalary;
        public Employee(int ages)
        {
          
            Random rnd = new Random();
            int nValue = rnd.Next(100); 
            while (nValue !=26)     //模擬類實例化執行很長時間
            {
                _baseSalary = ages * SALARYLEVEL * nValue / 100;
                nValue = rnd.Next(100);           
                System.Threading.Thread.Sleep(1000);
            }
    

           

        }

        //獲取加上獎金的工資
        public string GetBonusAndSalary(int nBonus)
        {
            return Convert.ToString(_baseSalary + nBonus);
        }


        //獲取基本工資
        public string GetBaseSalary()
        {
            return _baseSalary.ToString();
        }

 

    }
}

 

 

 

 

 

 

另,C#中不需要用鎖的線程安全的Singleton設計模式!

典型的線程安全的Singleton實現是使用double-checked locking的實現,但是在.NET中我們並不需要使用double-checked locking就可以優雅地實現Singleton模式。

這個優美的Singleton實現基礎是.NET對運行期初始化的完整定義。它的優美之處是不需要典型的double-checked locking。

當CLR加載class Singleton的時候,因爲Singleton沒有static variables需要被初始化,所以Singleton的初始化其實什麼也沒做。而對static class LazyHolder來說,直到它被執行的時候纔會被初始化。而static class LazyHolder只有載Singleton.GetInstance()被執行的時候纔會執行到。當第一次調用GetInstance()的時候 CLR纔會加載和初始化LazyHolder這個class。對於LazyHolder class的初始化就是對static variable Instance的初始化。而Instance的初始化就是執行Singleton的private constructor。因爲.NET保證class的initialization是serial的,就是說在加載和初始化的過程中我們不需要自己做同步。因爲初始化過程是一個serial的操作,所以對於後面的GetInstance,我們不需要做任何同步,它也會返回一個正確初始化的 Singleton對象。

實現代碼:

 

 1     public class Singleton
 2     {
 3         private static class LazyHolder
 4         {
 5             public static readonly Singleton Instance = new Singleton();
 6         }
 7 
 8         private Singleton()
 9         {
10         }
11 
12         public static Singleton GetInstance()
13         {
14             return LazyHolder.Instance;
15         }
16     }

 

 

#24樓 2007-01-17 18:14 | 網魂小兵      

這是Singleton設計模式的第五種實現方法,但是一般人都用
public class Singleton
{
private static readonly Singleton Instance = new Singleton();
static Singleton()
{
}

public static Singleton GetInstance()
{
return Instance;
}
}
這個吧!

 

#29樓 2007-01-18 00:28 | kevinshan[未註冊用戶]
不知道爲什麼要搞這麼複雜,在C#中這樣就可以了啊?

sealed class Singleton
{
private Singleton();
public static readonly Singleton Instance=new Singleton();
}

1,私有實例構造器保證了不會被實例化.
2,sealed保證了不會被繼承
3,readonly保證了實例化後的自動不會被修改
4,static 自動保證了線程安全的實例化.
5,沒有靜態構造函數保證了編譯器產生的構造函數是BeforeFieldInit,達到了lazy-load目的.

不過我覺的這種情況下爲什麼不要static class了?非要用Singleton模式?

  
#52樓 2007-08-27 20:35 | wqf[未註冊用戶]
需要這麼麻煩嗎?看代碼吧~~~
public class Singleton
{
private static Singleton Instance = null;

private Singleton()
{
}

static Singleton()
{
Instance = new Singleton();
}

public static Singleton GetInstance()
{
return Singleton.Instance;
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章