which singleton design pattern should be used ?

hi all, please help me choose the right singleton pattern.

  1. i am using a separate class with no Monobehavoiur.

  2. Should i use thread safe singleton pattern.

  3. Is there any performance hit if i use thread safe singleton pattern.


METHOD 1 : NOT THREAD SAFE

public sealed class Singleton
{
    private static Singleton instance = null;
       
    private Singleton()
    {
    }

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

METHOD2 : THREAD SAFE

public sealed class Singleton
{
    private static readonly object obj = new object();

    private Singleton()
    {
    }

    private static Singleton instance = null;

    public static Singleton GetInstance
    {
        get
        {
            if (instance == null)
            {
                lock (obj)
                {
                    if (instance == null)
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }
}

METHOD 3: THREAD SAFE

public sealed class Singleton
{
    private Singleton()
    {
    }

    private static readonly Lazy<Singleton> instance = 
                                new Lazy<Singleton>(()=>new Singleton());
       
    public static Singleton GetInstance
    {
        get
        {
            return instance.Value;
        }
    }  
}

If you don’t use Threading, you don’t need thread safety here. Unity is single-threaded for all your mono code.

In terms of performance, you’ll probably have to run some benchmarks. If you like, here’s a little benchmark helper class.

In addition to what’s been said already, I would also like to point out a beneficial use-case of Singletons.

Generally, when I find I need a Singleton, it really ends up acting as more of a Service; I send data to and from, and it helps manage a specific state, and I can call it statically throughout the application. One thing I realized as a result of this is that all my methods can be static, and I don’t really have a reason to allow the instance to be public.

For instance, I use this as a currency manager service in one of my projects:

using System;

public class CurrencyManager
{
     private static CurrencyManager instance = null;

     private int coins; 
        
     private CurrencyManager()
     {
         coins = 0;
     }

     // Notice even GetInstance() is private!
     private static CurrencyManager GetInstance()
     {
        if (instance == null)
        {
            instance = new CurrencyManager();
        }
        return instance; 
    }

    public static void Initialize(int previousCurrency)
    {
        CurrencyManager manager = GetInstance();
        Debug.Assert(manager != null);
        manager.coins = previousCurrency;
    }

    public static void AddCoins(int amount)
    {
        CurrencyManager manager = GetInstance();
        Debug.Assert(manager != null);
        manager.coins += amount;
    }

    public static int GetCurrencyAmount()
    {
        CurrencyManager manager = GetInstance();
        Debug.Assert(manager != null);
        return manager.coins;
    }

    public static bool Transact(int cost)
    {
        CurrencyManager manager = GetInstance();
        Debug.Assert(manager != null);

        if(manager.coins >= cost)
        {
            manager.coins -= cost;
            return true;
        }
        return false;
    }
}

I find the benefit to this Design Pattern is that it allows the functionality of the service to be entirely self-contained, and I can still call it universally throughout my application without slipping into the bad practice of having a god-like GameManager that has all-knowing references to major features of the application. I’ve made this mistake once and I realized it was a bad design decision when I started doing things like GameManager.instance.gameplaymanager.scoremanager..... While I fixed that, and to briefly contradict myself, I still use a GameManager as an all-knowing game initializer to load in data and make sure things are all prepared in a controlled order before allowing the main game scene to fully load. Whether or not it is a good design choice I will only know in time, but so far it’s better than it was!

I would look into scriptable object architecture, you can avoid using singletons altogether.