设计模式--单例模式--懒汉饿汉

单例模式

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式

通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

结构图

Singleton类,定义一个负责GetInstance操作,允许客户访问它的唯一实例。GetInstance是一个静态方法,主要负责创建自己的唯一实例。

java 复制代码
public class Singleton {
    
    private static Singleton instatnce;

    private Singleton() {   // 无参构造私有化,防止外部new对象
    }
    
    // 得到Singleton的实例,唯一的途径
    public static Singleton getInstance() { 
        if (instatnce == null) {
            instatnce = new Singleton();
        }
        return instatnce;
    }
}

客户端

java 复制代码
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();

if (s1 == s2) {
    System.out.println("对象相同");
}

多线程

另外还需要注意一些细节,比如,多线程的程序中,多个线程同时访问Singleton类,调用getInstance()方法时,会可能创建多个实例。我们需要加一些锁。

java 复制代码
public synchronized static Singleton getInstance() {
    if (instatnce == null) {
        instatnce = new Singleton();
    }
    return instatnce;
}

使用synchronized关键字锁住此方法,使得此方法在同一个时间点只有一个线程能进入访问。

这样看起来也没有问题,但是会有一个性能的问题:每次调用此方法的时候都需要锁,但其实我们只需要在创建instance 的时候让一个线程去创建就行。那么再改造一下。

双重锁定

java 复制代码
public class Singleton {

    private volatile static Singleton instatnce;

    private Singleton() {   // 无参构造私有化,防止外部new对象
    }

    // 得到Singleton的实例,唯一的途径
    public static Singleton getInstance() {
        if (instatnce == null) {
            synchronized (Singleton.class){	// 防止多个线程进入创建实例
                if (instatnce == null) {
                    instatnce = new Singleton();
                }
            }
        }
        return instatnce;
    }
}

使用volatile关键字,当synchronized变量被初始化成Singleton时,多个线程能正确处理synchronized变量。

synchronized 代码块儿中,还需要再加一层对instance的判断,因为当多个线程访问此方法时,它们都是通过了第一层instance==null的判断的,里面再加一层判断,防止后进入的线程又一次去创建实例。

静态初始化

在实际应用中,上面的做法都能应付自如。不过为了确保实例唯一,还是会带来很大的性能代价。对于性能要求很高的程序,建议还是采用静态初始化,也就是饿汉模式。

java 复制代码
public class Singleton {

    private static Singleton instatnce = new Singleton();

    private Singleton() {   // 无参构造私有化,防止外部new对象
    }

    // 得到Singleton的实例,唯一的途径
    public static Singleton getInstance() {
        return instatnce;
    }
}

这种静态初始化的方式是在自己被加载时就将自己实例化,所以被形象称之为饿汉式单例类。

要在第一次被引用时,才将自己实例化,则是被称之为懒汉式单例类。

大多数情况都是选择使用饿汉模式单例类,实际按项目需求做出选择。

相关推荐
阿维的博客日记4 小时前
设计模式-代理模式
设计模式·代理模式
笨手笨脚の4 小时前
设计模式-迭代器模式
java·设计模式·迭代器模式·行为型设计模式
o0向阳而生0o7 小时前
109、23种设计模式之迭代器模式(18/23)
设计模式·迭代器模式
笨手笨脚の12 小时前
设计模式-命令模式
设计模式·命令模式·行为型设计模式
adair-zhang12 小时前
23种设计模式
设计模式
十五年专注C++开发12 小时前
QT 中的元对象系统(六):connect函数详解
开发语言·c++·qt·设计模式·系统架构·qevent
Deschen13 小时前
设计模式-适配器模式
java·设计模式·适配器模式
Asort15 小时前
JavaScript设计模式(十一):享元模式(Flyweight) - 优化内存与性能的利器
前端·javascript·设计模式
Asort15 小时前
JavaScript设计模式(十)——外观模式 (Facade)
前端·javascript·设计模式
余辉zmh17 小时前
【C++篇】:LogStorm——基于多设计模式下的同步&异步高性能日志库项目
开发语言·c++·设计模式