【Java】设计模式之单例模式

2018-04-23  本文已影响25人  renkuo

工作有几年了,但是好多东西感觉没有沉淀下来,设计模式平时都在用,一些代码的技巧都是通过经验累积起来的,但是总感觉缺少一定的体系。很多东西会写,但是不会说,这就很尴尬。所以很多东西都要适当的整理一下,理论还是不能缺少的。比方说有人问你java特性,但是有的时候你可能一瞬间真的就卡住了,没办法通过专业名词表达出来。最近下定决心,花几个月的时间,把java的设计模式都整理出来。今天先整理一个个人认为大家都在用,而且比较经典的单例模式。不足之处欢迎大家指出,共同进步!∩▂∩站在巨人的肩膀上不停进步,哈哈。

UML类图

image.png

单例模式

双重检查加锁单例
如果性能是你关注的重点,这个做法可以大大地减少getInstance()的时间消耗。
因为这种方法并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。

public class Singleton {
//volatile关键词确保:当uniqueInstance变量被初始化成Singleton实例时,多线程正确处理uniqueInstance变量
    private volatile static Singleton uniqueInstance;
    private Singleton(){}
    public static Singleton getInstance(){
        if (uniqueInstance == null){
            synchronized (Singleton.class){
                if (uniqueInstance ==null){
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;  
}

静态单例
这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

public class Singleton {
    private Singleton(){}
    /**
     *    类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
     *    类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载
     */
    private static class SingletonHolder{
        /**
         * 静态初始化器,由JVM来保证线程安全
         */
        private static Singleton instance = new Singleton();
    }
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

枚举单例
单例的枚举实现在《Effective Java》中有提到,因为其功能完整、使用简洁、无偿地提供了序列化机制、在面对复杂的序列化或者反射攻击时仍然可以绝对防止多次实例化。这种方法的单例被认为是最好的单例。

public enum SingletonSourceEnum {
    INSTANCE;

    private Singleton1 singleton1;
    private SingletonSourceEnum() {
        singleton1 = new Singleton1();
    }
    public Singleton1 getInstance() {
        return singleton1;
    }
}
public class Singleton1 { }

验证方式如下:system.out输出的是true,结果表明两次获取的是一次实例

Singleton1 singleton1 = SingletonSourceEnum.INSTANCE.getInstance();
Singleton1 singleton2 = SingletonSourceEnum.INSTANCE.getInstance();
System.out.println(singleton1 == singleton2);

饿汉式单例
饿汉式是典型的空间换时间,当类装载的时候就会创建类的实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断,节省了运行时间。


public class Singleton2 {

    private static Singleton2 singleton = new Singleton2();

    private Singleton2(){}

    private static Singleton2 getInstance(){

        return singleton;
    }
}

懒汉式单例
懒汉式是典型的时间换空间,由于懒汉式的实现是线程安全的,这样会降低整个访问的速度,而且每次都要判断,比较浪费时间。

public class Singleton3 {

    private static Singleton3 singleton ;

    private Singleton3(){}

    private static synchronized Singleton3 getInstance(){
        if (singleton == null){
            singleton = new Singleton3();
        }

        return singleton;
    }
}

错误不足之处或相关建议欢迎大家评论指出,谢谢!如果觉得内容可以的话麻烦喜欢(♥)一下

上一篇下一篇

猜你喜欢

热点阅读