当前位置: 首页 > 开发语言 > C# > 设计模式 - 18)单例模式

设计模式 - 18)单例模式

时间:2021-01-09 14:02来源:未知 点击:
分享到:
class STWindow
{
    static Window win;
    private STWindow() { }
        
    public static Window GetInstance()
    {
        if (win == null || !win.IsVisible)
        {
            win = new Window();
            win.Height = 200;
            win.Width = 200;
        }
                    
        return win;
    }        
}

class Singleton
{
    static Singleton _singleton;
    private Singleton() { }

    public static Singleton GetInstance()
    {
        if (_singleton == null)
        {
            _singleton = new Singleton();
        }
        return _singleton;
    }
}

1. 多线程同时创建实例问题

多个线程同时访问 Singleton 的 GetInstance() 方法,可能会造成创建多个实例;
比如 A 先进入后在准备实例化 Singleton 的过程中,B 也进入了,这时 _singleton 还是为 null,然后 B 也去实例化 Singleton 了。

class Singleton
{
    static Singleton _singleton;
    private Singleton() { }

    public static Singleton GetInstance()
    {
        if (_singleton == null)
        {
            Console.WriteLine("实例化一个 Singleton");
            _singleton = new Singleton();
        }
        Console.WriteLine("返回一个 Singleton");
        return _singleton;
    }
}

System.Threading.Thread a = new System.Threading.Thread(() =>
{
    Singleton.GetInstance();
});

System.Threading.Thread b = new System.Threading.Thread(() =>
{
    Singleton.GetInstance();
});

System.Threading.Thread c = new System.Threading.Thread(() =>
{
    Singleton.GetInstance();
    });

a.Start();
b.Start();
c.Start();
实例化一个 Singleton
实例化一个 Singleton
返回一个 Singleton
返回一个 Singleton
返回一个 Singleton

我们通过加个锁来解决这个问题。

public static readonly object syncRoot = new object();

public static Singleton GetInstance()
{
    lock (syncRoot)
    {
        if (_singleton == null)
        {
            Console.WriteLine("实例化一个 Singleton");
            _singleton = new Singleton();
        }
    }
            
    Console.WriteLine("返回一个 Singleton");
    return _singleton;
}
实例化一个 Singleton
返回一个 Singleton
返回一个 Singleton
线程 0x1a08 已退出,返回值为 0 (0x0)。
返回一个 Singleton
线程 0x45b4 已退出,返回值为 0 (0x0)。
线程 0x5a04 已退出,返回值为 0 (0x0)。

2. 每次实例都要锁的性能问题

使用双重锁定,只有未实例化时才锁,锁完判断是否还未实例化。

public static Singleton GetInstance()
{
    if (_singleton == null)
    {
        lock (syncRoot)
        {
            if (_singleton == null)
            {
                _singleton = new Singleton();
            }
        }
    }
    return _singleton;
}

3.饿汉式单例

class Singleton
{
    static readonly Singleton _instance = new Singleton();

    private Singleton() { }

    public static Singleton GetInstance()
    {            
        return _instance;
    }
}

这种静态初始化的方式是自己被加载时就将自己实例化,因此被称为饿汉式单例;
而第一次被引用时才将自己实例化的方式被称为懒汉式单例。C# 中饿汉式已足够满足。

(责任编辑:admin)
推荐教程
关于我们--广告服务--免责声明--本站帮助-友情链接--版权声明--联系我们--网站地图          黑ICP备17004983号-1