设计模式之单例模式(饿汉模式,懒汉模式,双重检查加锁模式)

技术交流群:365814763

设计模式之单例模式(饿汉模式,懒汉模式,双重检查加锁模式)

单例模式,顾名思义只有一个单例,应用场景还是很普遍的,比如网站中的人数计数器、连接数据库中的连接实例等等。

单例模式:确保一个类只有一个实例,并提供一个全局访问点。到底怎么回事?即把某个类设计成自己管理的一个单独实例,同

时避免其他类再自行产生实例。要想取得实例,通过单例类是唯一的途径。也提供对这个实例的全局访问点:当你需要实例时,向

类查询,它会返回单个单例。

实现:

public class Singleton {

    private static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }

}

这种模式又称为懒汉模式(懒加载模式),是最基本的实现方式,最大的缺点是非线程安全的,一旦是多线程情况下,它就不能

正常使用了。延迟加载模式还有另一个特点,就是在使用到的时候才去加载,如果实例化的对象过程比较复杂,可能会出现卡顿

的情况,且当多线程情况下,可能会出现行为异常,那么如何解决线程安全问题呢?利用同步锁可以解决线程安全问题,实现如下:

public class Singleton {

    private static Singleton singleton;

    private Singleton() {
    }

    public synchronized static Singleton getSingleton() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

利用同步锁关键字synchronized,这样一来,在多线程情况下,访问获取单例就需要进行同步等待,达到线程安全问题。

而此时又会出现另一个问题,那就是性能问题,同步的时候线程访问方法出现等待的过程,性能大大降低,拖垮性能。那怎么

办?以下有一些方式可以改善问题。

1、如果getSingleton()的性能对应用程序不是很关键,或者是影响不大,可以什么都不做- -。。。

2、使用急切的方式(饿汉式)来初始化实例

实现如下:

public class Singleton {
    //饿汉式
    private static Singleton singleton = new Singleton();

    private Singleton() {
    }

    public static Singleton getSingleton() {
        return singleton;
    }
}

这种方式依赖JVM加载这个类时马上创建唯一的单例,缺点就是浪费内存,如果用不到的话。

3、双重检查加锁模式

public class Singleton {
    //双重检查加锁
    private volatile static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

用双重检查加锁,在getSingleton()中减少使用同步,首先检查是否实例已经创建了,如果尚未创建,“才”进行同步。这样一

来,只有第一次会同步,这正是我们想要的。

volatile关键词确保,当singleton变量被初始化成Singleton实例时,多个线程正确地处理singleton变量。

总结:

1、单例模式确保程序中一个类只有一个实例

2、单例模式也提供访问这个实例的全局点

3、在java中实现单例模式,需要一个静态变量,私有的静态构造器和一个公共的获取实例的方法

4、确定在性能和资源上的限制,然后小心地选择适合的方案来实现单例,以解决多线程的问题

5、如果你的类有多个类加载器,可能导致单例失效,而产生多个单例,可以选定类加载器来解决此问题

以上是对单例模式的一些理解。

 

你可能感兴趣的:(设计模式,设计模式,单例模式,饿汉式,懒汉式,双抽检查加锁模式)