专业编程基础技术教程

网站首页 > 基础教程 正文

单例模式,你真的懂了嘛(单例模式百科)

ccvgpt 2024-07-28 12:12:11 基础教程 7 ℃

定义

单例模式就是保证无论是在多线程还是单线程中,始终保证一个类只有一个实例,并提供一个全局的访问接口。

最佳实践:

单例模式,你真的懂了嘛(单例模式百科)

  • 将构造函数设置为private
  • 通过static修饰变量,保证全局仅有一个实例

使用场景:

  • 全局计数器
  • 唯一序列号
  • new一个资源比较耗时的对象,比如数据库连接对象

代码


一.双锁实现单例【懒汉式】

Bash
public class Singleton
{
    
    private static Singleton instance;
    private readonly static object syncObj=new object();
    
    private Singleton()
    {}
    
    public static Singleton GetInstance()
    {
        if(instance==null)
        {
            lock(syncObj)
            {
                if(instance==null)
                {
                    instance=new Singleton();
                    
                }
            }
        }
        return instance;
    }
    
}

上面的代码为什么需要对instance做了两次判断呢?

假设多个线程同事调用这个方法,同时判断instance==null,然后通过第一层拦截,此时其中一个加锁了,那么另外一个只能等待,此时加锁的线程已经创建了一个实例,此时再做一次判断,第二个线程就没必要再new一个实例了,这样可以保证始终只存在一个这个类的实例。

一定要保证构造函数式私有的,这样可以防止new ,此外可以阻止其他类继承。

这种方式一定是安全的嘛?

答案是否定的。因为存在编译器模型的内存优化,存在先new 了一个空壳子,但是这个对象并没有初始化完成,此时虽然intance不是空,拿到这个实例是没法用的,存在错误的可能

解决方案:使用内存栅栏或者volatile变量可以解决内存优化的问题

Bash
public sealed class Singleton
{
    private static Singleton instance = null;//volatile 可以禁止
    private static readonly object padlock = new object();

    Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        var tmp= new Singleton();
                        // ensures that the instance is well initialized,
                       // and only then, it assigns the static variable.
                        System.Threading.Thread.MemoryBarrier();
                       instance = tmp;
                    }
                }
            }
            return instance;
        }
    }
}

二.静态初始化实现单例【饿汉式】

这种方式和上面的双锁模式是类似的。

public  class  Singleton
{
    private static readonly Singleton instance=new Singleton();
    private Singleton()
    {}
    public Singleton GetInstance()
    {
        
        return instance;
    }
}

三. 使用Lasy实现单例

public class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());
    
    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
    
}

这种方式线程安全的,但是可能性能比较差,他是通过LazyThreadSafetyMode.ExecutionAndPublication用作Lazy<Singleton>的线程安全模式。

最近发表
标签列表