单例模式的两种写法:饿汉式单例和懒汉式单例

一般我们在项目开发中有时候常会遇到数据库的连接(不使用框架),我们常会在dao类中写一些通用的方法以供后面使用。一般的做法是哪里需要操作数据库的方法哪里就会创建一个对象,然后再引用对象里面的操作方法,这样做的不好的地方就是创建的对象比较多,比较消耗内存,降低程序效率,而我们完全可以只创建一个对象,然后哪里需要哪里就直接用,无需重新创建,这就是单例模式。

一、懒汉式单例(线程安全,推荐使用)

懒汉式单例顾名思义,它是驱动型的单例模式。当某个用户(线程)需要某个对象实例时才会去创建,而再未被需要之前不会主动去创建。在一些需要自己创建的工具类时,可以将其定义为一个单例类,因为在整个项目当中工具类只需要创建一次。

优缺点: 类加载较块,但获取对象较慢(需要先创建,仅针对第一次实例化),需要进行线程同步,保证线程安全。
注意: 在这个写法中用到了两次if(singleton == null)判断语句,因为当一个线程执行完if(singleton == null)还未执行下面的语句时,有另一个线程也执行完if语句,然后再执行下面的,此时会产生多个对象,线程不安全。但是当再加一个判断语句时,当某一个线程已经创建了该对象时,另一个线程在进行执行第二个if语句时直接返回false,从而不会创建多余的对象。

public class Singleton {//简单实现一个单例模型

    private static Singleton singleton ;
    private static Object object=new Object();
    /*私有化构造函数,使得在外部不能创建对象,这是实现单例模式的关键*/
    private Singleton(){}
    /*获取object对象锁,进行线程同步,在前一个线程未释放该锁时,其他线程需等待*/
   public static Singleton geiInstance(){
        if(util==null){
            synchronized (object){
                if(util==null){
                    util=new Singleton();
                }
            }
        }
        return util;
    }

    public static void main(String[] args) {
        Singleton singleton1 = Singleton.geiInstance();
        Singleton singleton2 = Singleton.geiInstance();
        System.out.println(singleton 1==singleton 2);
    }
}
//输出:true

二、饿汉式单例

饿汉式单例即主动型单例模式,不管用户用不用得到,它都会提前实例化对象等待用户调用。

优缺点: 在类加载时就已经实例化,因此类加载较慢,但获取对象比较快,不存在线程安不安全的问题。

public class Singleton {
    private static Singleton  singleton = new Singleton();
    private Singleton(){}
    public static Singleton getSingleton(){
        return singleton;
    }
    public static void main(String[] args) {
        Singleton util1= Singleton.getSingleton();
        Singleton util2= Singleton.getSingleton();
        System.out.println(util1==util2);
    }
}
//输出:true
<think>好的,用户让我用C#写两个单例模式子,一个是饿汉式,一个是懒汉。首先,我需要回忆下单例模式的基本概念,确保自己理解正确。单例模式确保一个类只有一个实,并提供全局访问点。饿汉式懒汉的主要区别在于实化的时机。 首先想饿汉式饿汉式是在类加载时就创建实,所以是线程安全的,因为静态初始化在C#中由CLR保证线程安全。那在C#中如何实现呢?应该是用静态变量,并在静态构造函数中初始化实。或者直接在声明静态变量时初始化。比如: public sealed class EagerSingleton { private static readonly EagerSingleton instance = new EagerSingleton(); private EagerSingleton() { } public static EagerSingleton Instance => instance; } 这样写的话,instance在类被加载时就初始化了,是线程安全的。对吗?需要检查一下C#的静态变量初始化时机。是的,静态变量在类第一次被使用时初始化,且由CLR保证线程安全,所以这样写是正确的饿汉式。 然后是懒汉懒汉是延迟加载,第一次访问时才创建实。需要考虑线程安全。最普通的懒汉不加锁的话,在多线程环境下可能会创建多个实。所以需要使用双重检查锁定或者其他机制。比如: public sealed class LazySingleton { private static volatile LazySingleton instance; private static readonly object lockObject = new object(); private LazySingleton() { } public static LazySingleton Instance { get { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new LazySingleton(); } } } return instance; } } } 这里要注意volatile关键字,防止指令重排序导致的问题。另外,双重检查锁定是否正确?是的,先检查是否为空,如果为空再进入锁,锁内再次检查,确保只创建一次实。 或者,C#中有更简洁的方,比如使用Lazy<T>类,这是推荐的方,因为Lazy<T>内部已经处理了线程安全。如: public sealed class LazySingleton { private static readonly Lazy<LazySingleton> lazy = new Lazy<LazySingleton>(() => new LazySingleton()); private LazySingleton() { } public static LazySingleton Instance => lazy.Value; } 这样更简洁,而且线程安全。用户可能更希望看到这两种实现方,传统的双重检查现代的Lazy<T>方。但用户可能要求的是传统的懒汉,所以可能需要两种写法都展示。 用户可能对线程安全的问题比较关心,需要解释为什么需要双重检查,以及volatile的作用。另外,可能需要指出在C#中推荐使用Lazy<T>来实现懒汉,因为它更简洁安全。 所以,总结回答的结构应该是先介绍单例模式,然后分别给出饿汉式懒汉的实现,并解释关键点,比如线程安全、延迟加载等。同时指出在C#中更推荐使用Lazy<T>来实现懒加载的。</think>以下是用C#实现的两种单例模式实现方案及对比分析: $$饿汉式$$ ```csharp public sealed class EagerSingleton { // 静态初始化在类加载时立即创建实 private static readonly EagerSingleton _instance = new EagerSingleton(); // 私有构造函数防止外部实化 private EagerSingleton() { } // 公共静态属性提供全局访问点 public static EagerSingleton Instance => _instance; } ``` $$懒汉$$ ```csharp public sealed class LazySingleton { // 使用Lazy<T>实现线程安全的延迟加载 private static readonly Lazy<LazySingleton> _lazy = new Lazy<LazySingleton>(() => new LazySingleton()); private LazySingleton() { } public static LazySingleton Instance => _lazy.Value; } ``` $对比说明:$ 1. 饿汉式特点: - 类加载时立即初始化(空间换时间) - 线程安全由CLR静态初始化机制保证 - 适合初始化耗时短且必定使用的场景 2. 懒汉特点: - 首次访问时才会创建实(时间换空间) - 使用.NET提供的$Lazy<T>$类型实现 - 内置双重检查锁定等线程安全机制 - 适合初始化耗时长或可能不使用的场景 $补充说明:$ 传统双重检查锁实现(理解原理用): ```csharp public sealed class ClassicLazySingleton { private static volatile ClassicLazySingleton _instance; private static readonly object _lock = new object(); private ClassicLazySingleton() { } public static ClassicLazySingleton Instance { get { if (_instance == null) { lock (_lock) { if (_instance == null) { _instance = new ClassicLazySingleton(); } } } return _instance; } } } ``` $最佳实践建议:$ - 在.NET环境中推荐使用$Lazy<T>$实现 - 需要严格控制初始化时机时使用饿汉式 - 若需实现复杂初始化逻辑,可在$Lazy<T>$的初始化委托中添加
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值