单例模式总结

1.定义

  单例模式,顾名思义,在该设计模式中,一个类只能存在一个实例。不能有超过一个实例的情况。
  下面的图片就是单例模式的类图:
这里写图片描述

2.应用场景

  单例模式的应用场景还挺多的。举个例子吧

  • windows系统的任务管理器
  • 回收站
  • 网站计数器

3. 单例模式的写法

3.1 懒汉式(线程不安全)

  在我们学习单例模式的时候,第一次给出我们的代码就是下面这个,最简单的代码。但是它有一个问题就是线程不安全。多线程的情况下可能产生多个实例。

public class Singleton{
    private static Singleton instance;
    Singleton(){}
    public static Singleton getInstance() {
        if(instance==null) {
            instance = new Singleton();
        }
        return instance;
    }
}

3.2 懒汉式(线程安全)

  为了改变上面单例模式的缺点,我们给getInstance()方法加上synchroized 关键字。具体代码如下:

public class Singleton{
    private static Singleton instance;
    Singleton(){}
    //加入了synchronized关键字
    public static synchronized Singleton getInstance() {
        if(instance==null) {
            instance = new Singleton();
        }
        return instance;
    }
}

3.3 饿汉式

  饿汉式的写法就是声明instance为static final类型的,在类加载的时候初始化类的实例。在getInstance()方法中直接返回类的实例。

public class Singleton{
    private  static final Singleton instance = new Singleton();
    Singleton(){}
    public static Singleton getInstance() {
        return instance;
    }
}

3.4 双重检验锁

  双重检验锁是为了解决懒汉式(线程安全)的多线程不高效的问题,在synchronized代码块中,判断instance的状态是否为空,保证instance的多线程安全性。

public class Singleton{
    private static Singleton instance;
    Singleton(){}
    public static Singleton getInstance() {
        if(instance==null) {
            synchronized(Singleton.class) {
                if(instance==null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

但是这里有一个问题就是,如果执行以下的代码会产生单例生成不一致的情况。主要是在代码的第8行,当代码读取到instance不为null的时候,instance引用的对象可能还没有完成初始化。

instance = new Singleton();

这个代码可以分解为下面三行伪代码:

memory = allocate();    //1: 分配对象的内存空间
ctorInstance(memory);   //2: 初始化对象
instance = memory;      //3:设置instance指向刚分配的内存地址。

在上述的代码中第二行和第三行可能会进行指令的重排序。
这就导致了问题的出现。
当我们把instance设置成volatile类型的时候,因为volatile禁止了指令的重排序所以类似问题得到了解决。

public class Singleton{
    private volatile static Singleton instance;
    Singleton(){}
    public static Singleton getInstance() {
        if(instance==null) {
            synchronized(Singleton.class) {
                if(instance==null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

3.5 静态内部类

  在《Effective Java》中,推荐用此类方法。即保证多线程的安全性,又保证了高效性。

public class Singleton{
    private static class SingletonHolder{
        private static final Singleton INATANCE = new Singleton();
    }
    Singleton(){}
    public static Singleton getInstance() {
        return SingletonHolder.INATANCE;
    }
}

3.6 枚举

public enum EasySingleton{
    INSTANCE:
}

  在枚举类型的单例模式中,是最简单的单例模式的写法,可以直接通过EasySingleton.INSTANCE来访问实例。

4. 总结

这里一共列举了六种单例模式的写法,准确的说是5种,这里推荐的是静态内部类来实现单例模式,在保证并发的高效性的情况下,又保证了线程安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值