单例模式

设计模式-单例模式

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

有时候,我们要求一个类仅有一个实例,这种场景下单例模式就可以派上用场。先看下单例模式的类图。

UML类图

这里写图片描述

单例模式的关键是构造函数定义为私有的,防止在外部实例化该类对象,并提供一个获取单例对象的公共方法。

代码实现

单例模式实现可分为单线程和多线程的,也即是否线程安全的。

单线程的单例
/**
 * <p>文件描述: 单线程的单例</p>
 *
 * @Author luanmousheng
 * @Date 17/6/25 下午2:48
*/
public class Singleton {
    private static Singleton instance;

    private Singleton() {

    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
多线程的单例

多线程下创建单例不是线程安全的,有两种方式可以解决这个问题,DCL加锁机制和静态初始化机制。加锁保证了同时只有一个线程去创建单例,静态初始化是借助了类加载机制。

双重检查锁定(Double Check Locking, DCL)
/**
 * <p>文件描述: 双重检查锁定机制:DCL</p>
 *
 * @Author luanmousheng
 * @Date 17/6/25 下午2:59
*/
public class Singleton {

    private static volatile Singleton singleton;

    private Singleton() {

    }

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

双重检查锁定的第一次检查,是为了判断实例是否已经存在,只有当实例不存在才会去创建,否则每次调用getInstance方法都要去做同步锁定,效率太低。

在第一次检查和第二次检查之间的同步块,是为了保证同时只有一个线程创建实例对象。

那为何要有第二次检查呢?假如一开始单例实例不存在,A和B线程都通过了第一次检查,假设线程A竞争到了同步锁,进入到了同步块内,直接创建实例。当线程A离开同步块后,线程B拿到同步锁并进入到同步块,也会创建实例,那就创建了两次实例。因此第二次检查是必要的。

静态变量singleton为何被声明为volatile的?singleton = new Singleton()不是原子的操作,将singleton声明为volatile,禁止了指令重排序,防止其他线程拿到了还未初始化完成的对象引用(CPU可能先给singleton赋值为对象的地址,然后去初始化对象,此时其他线程就可能拿到未初始化完成的对象引用)。

静态初始化机制

静态初始化机制包括类静态变量的初始化和静态块的初始化

静态变量初始化
/**
 * <p>文件描述: 静态变量初始化</p>
 *
 * @Author luanmousheng
 * @Date 17/6/25 下午3:33
*/
public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return instance;
    }
}

这种方法利用了类加载机制,类加载的时候就创建了对象。

静态块初始化
/**
 * <p>文件描述: 静态内部类机制</p>
 *
 * @Author luanmousheng
 * @Date 17/6/25 下午3:40
*/
public class Singleton {

    /**
     * 静态内部类
     */
    private static class SingletonHolder {
        private static final Singleton instance = new Singleton();
    }

    /**
     * <p>功能描述: 只有真正调用该方法时才会去初始化instance</p>
     *
     * @Author luanmousheng
     * @Date 17/6/25 下午3:42
    */
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

这种方式最大的优点是延迟初始化,只有在需要的时候才会去创建实例。

参考:

  1. 大话设计模式. 程杰著
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值