单例模式之学习笔记

双重检查加锁实现

可以使用“双重检查加锁”的方式来实现单例模式,就可以既实现线程安全,又能够使性能不受到大的影响。

所谓双重检查加锁机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检
查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
双重检查加锁机制的实现会使用一个关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
注意:在Java1.4及以前版本中,很多JVM对于volatile关键字的实现有问题,会导致双重检查加锁的失败,因此双重检查加锁的机制只能用在Java5及以上的版本。
看看代码可能会更清楚些,示例代码如下:
public class Singleton {
 /**
  * 对保存实例的变量添加volatile的修饰
  */
 private volatile static Singleton instance = null;

 private Singleton() {
 }

 public static Singleton getInstance() {
  // 先检查实例是否存在,如果不存在才进入下面的同步块
  if (instance == null) {
   // 同步块,线程安全的创建实例
   synchronized (Singleton.class) {
    // 再次检查实例是否存在,如果不存在才真的创建实例
    if (instance == null) {
     instance = new Singleton();
    }
   }
  }
  return instance;
 }
}

单例模式的懒汉式实现方式体现了延迟加载的思想,即一开始不要加载资源或者数据,一直等,等到马上就要使用这个资源或者数据了,躲不过去了才加载,所以也称Lazy Load,不是懒惰啊,是“延迟加载”,这在实际开发中是一种很常见的思想,尽可能的节约资源。

需要先得到类实例,然后才可以调用,可是这个方法就是为了得到类实例,这样一来不就形成一个死循环了吗
public static Singleton getInstance() {}

更好的方案
要想很简单的实现线程安全,可以采用静态初始化器的方式,它可以由JVM来保证线程安全性。比如前面的“饿汉式”实现方式,但是这样一来,不是会浪费一定的空间吗?因为这种实现方式,会在类装载的时候就
初始化对象,不管你需不需要。
如果现在有一种方法能够让类装载的时候不去初始化对象,那不就解决问题了?一种可行的方式就是采用类级内部类,在这个类级内部类里面去创建对象实例,这样一来,只要不使用到这个类级内部类,那就不会创建对象实例。从而同时实现延迟加载和线程安全。
看看代码示例可能会更清晰,示例代码如下:
public class SingletonT {
 /**
  * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
  * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
  */
 private static class SingletonHolder {
  /**
   * 静态初始化器,由JVM来保证线程安全
   */
  private static SingletonT instance = new SingletonT();
 }

 /**
  * 私有化构造方法
  */
 private SingletonT() {
 }

 public static SingletonT getInstance() {
  return SingletonHolder.instance;
 }
}
仔细想想,是不是很巧妙呢!
当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建
Singleton的实例,由于是静态的域,因此只会被虚拟机在装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。
这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值