欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式-单例模式改进

程序员文章站 2024-01-24 09:22:40
...

对原单例模式改进

原单例模式存在缺陷

原单例模式的实现在多线程场景下,在线程1判断实例为空之后实例化赋值之前,另外一个线程开始判断实例为空,这时两个线程的判断结果都是实例对象为空,从而都创建实例,导致两个线程中获取的实例不是同一个实例

改进思路1

既然多线程获取实例时,可能会存在问题,那么只需要对获取实例的方法加锁,这样就不会出现以上问题

改进实现1

package com.qsy.singleton.advanced;

/**
 * <pre>更高级的单例模式,主要考虑多线程情况下</pre>
 * @author yangsx
 * @date 2019年9月18日
 */
public class SingletonBean {
    
    
    private static SingletonBean uniqueInstance = null;

    /**
     * <pre>构造函数私有化</pre>
     * @author yangsx
     * @date 2019年9月18日
     */
    private SingletonBean() {
        
    }
    
    /**
     * <pre>共有静态方法对外提供实例</pre>
     * 获取实例时,多线程可能会出现返回多个实例的问题,主要考虑在new之前,另外一个线程也在判断空
     * 初次创建实例时,多个线程竞争锁就会消耗过多资源
     * @author yangsx
     * @date 2019年9月18日
     * @return
     */
    public synchronized static SingletonBean getInstace() {
        if (uniqueInstance == null) {
            uniqueInstance = new SingletonBean();
        }
        return uniqueInstance;
    }
    
}

改进实现 1存在的缺陷

直接对静态方法加锁,会导致每一次获取实例时都要获取锁资源,在频繁的调用下,每次调用都可能等待占用资源。

分析根本原因是因为多线程下,判断null为空可能会同时执行,只要让实例变量永远不为空,这样就永远能够返回单一实例且不存在冲突问题

改进实现2

package com.qsy.singleton.advanced;

/**
 * <pre>更高级的单例模式,主要考虑多线程情况下</pre>
 * <pre>饥汉模式</pre>
 * @author yangsx
 * @date 2019年9月18日
 */
public class SingletonBean2 {
    
    /**
     * 体现饥汉模式
     * 不用的时候存在内存浪费
     */
    private static SingletonBean2 uniqueInstance = new SingletonBean2();

    /**
     * <pre>构造函数私有化</pre>
     * @author yangsx
     * @date 2019年9月18日
     */
    private SingletonBean2() {
        
    }
    
    /**
     * <pre>公有静态方法对外提供实例</pre>
     * @author yangsx
     * @date 2019年9月18日
     * @return
     */
    public static SingletonBean2 getInstace() {
//        if (uniqueInstance == null) {
//            uniqueInstance = new SingletonBean2();
//        }
        return uniqueInstance;
    }
    
}

改进实现2存在的缺陷

正如代码中所说,当不需要使用当前实例时,就会存在内存浪费,所以有如下改进

改进实现3

package com.qsy.singleton.advanced;

/**
 * <pre>双重检查加锁法实现单例模式</pre>
 * @author yangsx
 * @date 2019年9月18日
 */
public class SingletonBean3 {
    
    /**
     * volatile多线程可见
     */
    private volatile static SingletonBean3 uniqueInstance = null;

    /**
     * <pre>构造函数私有化</pre>
     * @author yangsx
     * @date 2019年9月18日
     */
    private SingletonBean3() {
        
    }
    
    /**
     * <pre>公有静态方法对外提供实例
     * 双重校验加锁
     * </pre>
     * @author yangsx
     * @date 2019年9月18日
     * @return
     */
    public static SingletonBean3 getInstace() {
        if (uniqueInstance == null) {
            // 方法不会加锁,只要创建过一次,就不会再存在锁竞争
            synchronized (SingletonBean3.class) {
                // 确保获取锁之后uniqueInstance没有被创建才需要创建实例
                if (uniqueInstance == null) {
                    uniqueInstance = new SingletonBean3();
                }
            }
        }
        return uniqueInstance;
    }
    
}