读《设计模式:可复用面向对象软件的基础》--创建型模式之单例模式(Singleton)

单例模式

意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

动机

单例模式动机

适用性

需要确保一个类的实例必须全局唯一,并且可以全局访问。

结构

结构

优点

  1. 对唯一实例的受控访问。
  2. 缩小名空间,可以避免那些存储唯一实例的全局变量污染名空间。

实现

懒汉式(线程不安全)
public class Singleton01 {

    /**
     * 默认不再初始化
     */
    private static Singleton01 singleton = null;

    /**
     * 构造器私有
     */
    private Singleton01(){

    }

    /**
     * 暴露出实例方法
     */
    public  static  Singleton01 getInstance(){
        if(singleton == null ){
            singleton = new Singleton01();
        }
        return singleton;
    }
}
饿汉式(线程安全)
public class Singleton {
    /**
     * 自己构造自己的实例,设置private,外界无法访问
     */
    private static final Singleton singleton = new Singleton();

    /**
     * 构造器私有,外界无法通过new关键字创建对象
     */
    private  Singleton(){

    }

    /**
     * 暴露得到实例的方法
     */

    public static  Singleton getInstance(){
        return singleton;
    }
}
懒汉式(线程安全)
public class Singleton01 {

    /**
     * 默认不再初始化
     */
    private static Singleton01 singleton = null;

    /**
     * 构造器私有
     */
    private Singleton01(){

    }

    /**
     * 暴露出实例方法
     * synchronized对性能影响特别大,每次访问都会加锁
     */
    public  static  synchronized  Singleton01 getInstance(){
        if(singleton == null ){
            singleton = new Singleton01();
        }
        return singleton;
    }
}
懒汉式–双重校验锁(线程安全)
public class Singleton02 {
    private volatile static Singleton02 singleton = null;
    private Singleton02(){ }
    /**
     * 暴露出实例方法
     * synchronized加上可以保证线程安全,但是会大幅度降低系统性能,因为每次请求都加锁。
     */
    public  static  Singleton02 getInstance(){
    	//加锁前检测
        if(singleton == null ){
            synchronized (Singleton02.class){
            	//加锁后检测
                if(singleton == null){
                    singleton = new Singleton02();
                }
            }
        }
        return  singleton;
    }
}
单层锁为什么不行?
if (singleton == null) {
    synchronized (Singleton02.class) {
        singleton = new Singleton02();
    }
}

假如两个线程同时执行了if (singleton == null)语句,并且都通过了if检测,即使if语句里面有synchronized锁, singleton = new Singleton02()依然会被两个线程分别执行一次,因为假如第一个先进入同步代码块执行,第二个线程等待,当第一个执行结束,第二个依然可以获得锁去执行。

静态内部类实现

利用静态内部类仅在类初始化的时候加载一次的性质。该实现也属于懒汉式,因为刚Singleton初始化的时候private static final Singleton INSTANCE = new Singleton()并不会执行,只有调用getUniqueInstance方法的时候才会执行。

public class Singleton {

    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getUniqueInstance() {
        return SingletonHolder.INSTANCE;
    }
}
枚举实现(重要)

这是单例模式的最佳实践,它实现简单,并且在面对复杂的序列化或者反射攻击的时候,能够防止实例化多次。

public enum Singleton{
    /**
     * 唯一实例
     */
    uniqueInstance;
    private Singleton(){
        System.out.println("here");
    }
    public void doSomething(){
        System.out.println("hello");
    }
    public static void main(String[] args) {
        //在此执行了私有方法,也即执行new Singleton()的地方
        Singleton uniqueInstance = Singleton.uniqueInstance;
        // Singleton uniqueInstance2 = Singleton.uniqueInstance;
        // System.out.println(uniqueInstance.equals(uniqueInstance2)); true
        //调用一些方法
        uniqueInstance.doSomething();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w͏l͏j͏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值