`

Java 中的双重检查(Double-Check)

阅读更多

        在 Effecitve Java 一书的第 48 条中提到了双重检查模式,并指出这种模式在 Java 中通常并不适用。该模式的结构如下所示:

public Resource getResource() {
  if (resource == null) { 
    synchronized(this){ 
      if (resource==null) {
        resource = new Resource();  
      }   
    }  
  }
  return resource;
}

        该模式是对下面的代码改进:

public synchronized Resource getResource(){
  if (resource == null){ 
        resource = new Resource();  
  }
  return resource;
}

        这段代码的目的是对 resource 延迟初始化。但是每次访问的时候都需要同步。为了减少同步的开销,于是有了双重检查模式。

        在 Java 中双重检查模式无效的原因是在不同步的情况下引用类型不是线程安全的。对于除了 long 和 double 的基本类型,双重检查模式是适用 的。比如下面这段代码就是正确的:

private int count;
public int getCount(){
  if (count == 0){ 
    synchronized(this){ 
      if (count == 0){
        count = computeCount();  //一个耗时的计算
      }   
    }  
  }
  return count;
}

        上面就是关于java中双重检查模式(double-check idiom)的一般结论。但是事情还没有结束,因为java的内存模式也在改进中。Doug Lea 在他的文章中写道:“根据最新的 JSR133 的 Java 内存模型,如果将引用类型声明为 volatile,双重检查模式就可以工作了”,参见http://gee.cs.oswego.edu/dl/cpj/updates.html

        所以以后要在 Java 中使用双重检查模式,可以使用下面的代码:

private volatile Resource resource;
public Resource getResource(){
  if (resource == null){ 
    synchronized(this){ 
      if (resource==null){
        resource = new Resource();  
      }   
    }  
  }
  return resource;
}

        当然了,得是在遵循 JSR133 规范的 Java 中。

        所以,double-check 在 J2SE 1.4 或早期版本在多线程或者 JVM 调优时由于 out-of-order writes,是不可用的。 这个问题在 J2SE 5.0 中已经被修复,可以使用 volatile 关键字来保证多线程下的单例。

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

        推荐方法 是Initialization on Demand Holder(IODH),详见 http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

public class Something {
    private Something() {}

    private static class LazyHolder {
        private static final Something instance = new Something();
    }

    public static Something getInstance() {
        return LazyHolder.instance;
    }
}

 

文章来源:http://blog.csdn.net/dl88250/article/details/5439024

分享到:
评论

相关推荐

    Java中的双重检查(Double-Check)详解

    Java中的双重检查(Double-Check)是一种用于实现线程安全单例模式的设计策略,它的核心思想是在确保对象只被初始化一次的同时,尽可能地减少同步的使用以提高性能。然而,在早期的Java版本中,双重检查模式存在一些...

    从单例谈double-check必要性,多种单例各取所需.doc

    为解决此问题,通常会使用双重检查锁定(Double-Check Locking),在上述代码中添加了同步机制,保证了线程安全。 4. **双检锁/双重检查锁定(DCL)**: - 在懒汉式的基础上,通过两次检查`person`是否为null来...

    java设计模式----单例模式

    在实际应用中,有一种改进的懒汉模式,称为双重检查锁定(Double-Check Locking),它在保证线程安全的同时,提高了性能。这种方式在`getInstance()`方法中添加了额外的检查,确保只有在实例真正为null时才进行同步...

    java代码-double check单例模式

    在Java中,实现单例模式有多种方式,其中“double check”(双重检查锁定)是线程安全的单例模式实现之一,它兼顾了性能和线程安全性。 首先,我们要理解为什么需要双重检查锁定。在早期的Java版本中,由于JVM的...

    java-thread-safe-singleton-pattern.rar_starvation

    上述代码是典型的双检锁/双重校验锁(DCL,Double-Check Locking)单例模式,它结合了静态内部类和 volatile 关键字来实现延迟加载和线程安全,避免了饥饿问题。 **延迟加载(Lazy Initialization)**: 延迟加载是...

    java之设计模式--各种设计模式解析

    实现单例通常采用双重检查锁定(Double-Check Locking)或静态内部类等方式,确保线程安全且只创建一次实例。 接下来是命令模式。命令模式将请求封装为一个对象,使得可以使用不同的请求、队列请求、或者支持撤销...

    【Java面试资料】-(机构内训资料)上海-拼多多-Java高级

    - 双重检查锁定(Double-Check Locking)与初始化-on-demand holder类设计模式。 5. **IO流与NIO** - 流的分类:字节流与字符流,输入流与输出流,缓冲流与转换流。 - 文件操作:File类的常用方法,文件复制与...

    Java 版设计模式学习笔记-java-design-patterns.zip

    在Java中,通常使用双重检查锁定(Double-Check Locking)或者静态内部类的方式实现单例,以确保线程安全并避免过早初始化。 二、工厂模式 工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在Java...

    java单例设计模式-饿汉式-懒汉式.pdf

    除了同步方法,Java 还提供了双重检查锁定(Double-Check Locking)策略,这是一种更高效的懒汉式实现方式,它减少了同步的范围: ```java public class Singleton { private volatile static Singleton instance;...

    计算机后端-Java-Java高并发从入门到面试教程-发课程资料.zip

    - **Double-Check Locking**:理解双重检查锁定模式,以及其在单例模式中的应用。 - ** volatile与synchronized的区别**:深入探讨两者的异同。 通过本课程的学习,开发者不仅能掌握Java并发编程的基础知识,还能...

    java单例设计模式-饿汉式-懒汉式[参照].pdf

    为了解决懒汉式的线程安全问题,可以采用双重检查锁定(Double-Check Locking)策略,这是一种更高效的实现方式: ```java public class Singleton { private volatile static Singleton instance; private ...

    Java-Core-Interview-Examples:有关常见Java面试编码问题的示例类文件

    - 懒汉式(Lazy Initialization):首次调用getInstance()时才创建实例,可能不线程安全,可以使用synchronized关键字或双重检查锁定(Double-Check Locking)来实现线程安全。 - 静态内部类:利用类装载机制保证...

    FastJava-源码.rar

    源码中,我们可能会发现使用了位运算、双重检查锁定(Double-Check Locking)等高级编程技术来提升并发性能和内存管理。 FastJava还可能关注了内存效率,避免了不必要的对象创建。在Java中,频繁的对象创建会增加...

    java中的单例模式

    为了兼顾线程安全和性能,可以使用双重检查锁定(Double-Check Locking)优化懒汉式: ```java public class Singleton { private volatile static Singleton instance; private Singleton() {} public static...

    java单例设计模式-饿汉式-懒汉式 (2).pdf

    ### 双重检查锁定(Double-Check Locking) 为了提高性能,我们可以使用双重检查锁定来进一步优化懒汉式。这种方法只在真正需要创建实例时进行同步,其余时间则不进行同步。代码如下: ```java public class ...

    java单例设计模式-饿汉式-懒汉式 (2).docx

    为了解决性能问题,可以使用双重检查锁定(Double-Check Locking)优化懒汉式单例: ```java public class Singleton { private volatile static Singleton instance; private Singleton() {} public static ...

    应聘Java笔试时可能出现问题及其答案

    在Java中,可以使用双检锁/双重检查锁定(Double-Check Locking)实现线程安全的单例。 通过深入理解这些Java编程的关键概念和实践,你将在Java笔试中更有信心,更好地应对各种技术挑战。不断练习和巩固这些知识,...

    Java多线程设计模式_清晰完整PDF版 Java多线程设计模式源代码

    Java中双检锁/双重检查锁定(Double-Check Locking,DCL)和静态内部类是实现线程安全单例的常用方法。 5. 状态对象模式:用于在多线程中同步访问对象的状态,例如CountDownLatch、CyclicBarrier和Semaphore等并发...

Global site tag (gtag.js) - Google Analytics