Design mode – 18) singleton mode

Time:2021-9-6
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. The problem of multiple threads creating instances at the same time

If multiple threads access the getinstance() method of singleton at the same time, multiple instances may be created;
For example, a enters first, and then B also enters in the process of preparing to instantiate singleton. At this time_ Singleton is still null, and then B instantiates singleton.

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

    public static Singleton GetInstance()
    {
        if (_singleton == null)
        {
            Console. Writeline ("instantiate a singleton");
            _singleton = new Singleton();
        }
        Console. Writeline ("return a 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();
Instantiate a singleton
Instantiate a singleton
Returns a singleton
Returns a singleton
Returns a singleton

We solve this problem by adding a lock.

public static readonly object syncRoot = new object();

public static Singleton GetInstance()
{
    lock (syncRoot)
    {
        if (_singleton == null)
        {
            Console. Writeline ("instantiate a singleton");
            _singleton = new Singleton();
        }
    }
            
    Console. Writeline ("return a singleton");
    return _singleton;
}
Instantiate a singleton
Returns a singleton
Returns a singleton
Thread 0x1a08 exited with a return value of 0 (0x0).
Returns a singleton
Thread 0x45b4 exited with a return value of 0 (0x0).
Thread 0x5a04 exited with a return value of 0 (0x0).

2. Performance problems of locking every instance

Double locking is used to lock only when it is not instantiated. After locking, judge whether it has not been instantiated.

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

3. Hungry Han style single example

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

    private Singleton() { }

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

This static initialization method instantiates itself when it is loaded, so it is called hungry Han singleton;
The method of instantiating itself when it is referenced for the first time is called lazy singleton. C # the hungry Chinese style is enough.