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

设计模式-Singleton

程序员文章站 2022-07-06 11:34:30
...
单例模式:
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。


单例模式的特点:
单例类只能有一个实例。
单例类必须自己创建自己的唯一实例。
单例类必须给所有其他对象提供这一实例。


单例模式是最简单的设计模式,但是完全使用java构造一个线程安全的高效的单例,是需要有一定线程安全理论基础的,甚至需要理解java的内存模型!

JDK中的使用案例:
java.lang.Runtime
java.lang.NumberFormat

下面是三种最常用的构造单例的形式,并一一分析使用场景!

1、非延迟加载的单例类(饿汉式单例类)。
/**
 * 非延迟加载(这种是比较建议的,但是会造成启动较慢,不过线程安全,思路也简单)
 * @author xinchun.wang
 *
 */
public class SingletonDesign {
    private static SingletonDesign instance = new SingletonDesign();

    /**
     * 必须为私有
     */
    private SingletonDesign(){
        
    }
    
    /**
     * 必须为静态
     * @return
     */
    public static SingletonDesign getInstance() {
        return instance;
    }
}


2、二次检查的方式(DCL)。

/**
 * 延迟加载(二次检查的方式)
 * @author xinchun.wang
 * 
 */
public class SingletonDesignDoubleCheck {
    /**
     * 此处必须由volatile 修饰
     */
    private volatile static SingletonDesignDoubleCheck instance = null;

    /**
     * 必须为私有
     */
    private SingletonDesignDoubleCheck() {

    }

    /**
     * 必须为静态
     * 
     * @return
     */
    public static SingletonDesignDoubleCheck getInstance() {
        if (instance == null) {
            synchronized (SingletonDesignDoubleCheck.class) {
                //必须再次判断,已防止多次实例化
                if(instance == null){
                    instance = new SingletonDesignDoubleCheck();
                }
            }
        }
        return instance;
    }
}

此处重点要理解 为什么instance 要用volitile修饰,大家都知道volitile 实现的效果有:内存可见性,代码重排序。那么此处是用到那个效果呢?

其实此处最重要的是重排序,而非内存可见性:即使没有保证内存可见性的效果,最多也就是再次进入synchronized 块,内部仍然是可以确保逻辑的正确性的。当然内存可见性可以确保写线程写入后,读线程立即可以看到而不用再次获取SingletonDesignDoubleCheck.class锁 ,效率更高。

此处的重排序关键是搞清楚到底是那段代码的重排序,以及导致什么样的一个效果?
答案是:instance 赋值指令 和  SingletonDesignDoubleCheck 构造函数里成员常量的重排序,非法的效果是:赋值在前,初始化在后,这样赋值的instance是没有完全初始化的,其他线程就会看到不完整的instance实例!!!  
这样的分析,不知道您是否理解~    

3、利用了java的类加载机制的一个实现(这个是实际应用中最推荐的方式,但是这种方式在某些需要定期更新的需求,是做不到的,必须求救于DCL的方式)
/**
 * holder方式(这种方式主要是利用了java的类加载机制)
 * @author xinchun.wang
 *
 */
public class SingletonDesignByHolder {
    private static class SingletonDesignHolder{
        private static final SingletonDesignByHolder instance = new SingletonDesignByHolder();
    }

    /**
     * 必须为私有
     */
    private SingletonDesignByHolder(){
        
    }
    
    /**
     * 必须为静态
     * @return
     */
    public static SingletonDesignByHolder getInstance() {
        return SingletonDesignHolder.instance;
    }
}