Java并发编程实战--双重检查加锁( double check lock)与延迟初始化占位

DCL

     在任何一本介绍并发的书中都会讨论声名狼藉的双重检查加锁(DCL)。
     下图来自:http://zoroeye.iteye.com/blog/2058889
Java并发编程实战--双重检查加锁( double check lock)与延迟初始化占位_第1张图片

     DCL的真正问题在于:当在没有同步的情况下读取一个共享对象时,可能发生的最糟糕的事情只是看到一个失效值(在这种情况下是一个空值),此时DCL方法将通过在持有锁的情况下在此尝试来避免这种风险。然而,实际情况远比这种情况糟糕——线程可能看到引用的当前值,但对象的状态值却是失效的,这意味着线程可以看到对象处于无效或错误的状态。

     在JVM的后续版本(Java5.0以及更高的版本)中,如果把resource声明为volatile类型,那么就能修正这个问题。

public class DoubleCheckedLocking {
    //对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
    private volatile static Resource resource;

    public static Resource getInstance() {
        if (resource == null) {
            synchronized (DoubleCheckedLocking.class) {
                if (resource == null)
                    resource = new Resource();
            }
        }
        return resource;
    }

    static class Resource {

    }
}

     缺乏同步会导致无法实现可见性,这使得确定何时写入对象引用而不是原语值变得更加困难。在缺乏同步的情况下,可能会遇到某个对象引用的更新值(由另一个线程写入)和该对象状态的旧值同时存在。(这就是造成著名的双重检查锁定(double-checked-locking)问题的根源,其中对象引用在没有同步的情况下进行读操作,产生的问题是您可能会看到一个更新的引用,但是仍然会通过该引用看到不完全构造的对象)。

     DCL方法已经被广泛地废弃了,延迟初始化占位类模式能带来同样的优势,并且更容易理解。

延迟初始化占位

     使用一个专门的类来初始化Resource。JVM将推迟ResourceHolder的初始化操作,直到开始使用这个类时才初始化,并且由于通过一个静态初始化来初始化Resource,因此不需要额外的同步。当任何一个线程第一次调用getResouce时,都会使ResouceHolder被加载和被初始化,此时静态初始化器将执行Resource的初始化操作。

public class ResourceFactory {
     private static class ResourceHolder {
         public static Resource resource = new Resource();
     }

     public static Resource getResource() {
         return  ResourceHolder.resource ;
     }
}

Java并发编程实战pdf及案例源码下载:
http://download.csdn.net/detail/xunzaosiyecao/9851028

作者:jiankunking 出处:http://blog.csdn.net/jiankunking

你可能感兴趣的:(Java,Java,进阶)