【问题标题】:Why don't we require a lazy-init getter to be synchronized (the holder idiom)?为什么我们不需要同步惰性初始化 getter(持有者习语)?
【发布时间】:2015-11-18 06:23:51
【问题描述】:

我正在阅读 J. Bloch 的有效 Java,现在我正在阅读关于延迟初始化的部分。考虑以下类:

public class LazyInit{

    public static getObject(){  //Not synchronized
        return Holder.o;
    }

    private static Object createObject(){
        System.out.println("Creating started");
        return new Object();
    }

    private static class Holder{
        private static Object o = createObject();
    }
}

J。布洛赫谈到了这个成语:

这个成语的美妙之处在于getField方法不是 同步并且只执行一个字段访问,所以很懒 初始化几乎不会增加访问成本。

我不明白为什么它可以安全通过。如果在字段初始化期间另一个线程尝试同时访问该字段怎么办?该对象在线程需要它时并未创建。那么,会发生什么?

【问题讨论】:

    标签: java multithreading lazy-initialization


    【解决方案1】:

    这种方法是基于 JVM 的初始化原则。

    Object 的实例将仅在加载 Holder 类后创建。 Holder 类的加载将由类加载器在您的应用程序中首次引用字段 o 期间执行(这里是 getObject 方法)。类加载是非最新的,所以这个模式保证:

    1. Object 实例将按需创建(延迟初始化)。
    2. Object 的创建将是线程安全的。

    取自wiki article

    由于 JLS 保证类初始化阶段是串行的,即非并发的,因此在加载和初始化期间,静态 getInstance 方法不需要进一步同步。


    来自 cmets 的更新:

    @St.Antario 发现 formal JLS explanation 用于此功能:

    然后初始化 C 的过程如下:在 C 的初始化锁 LC 上同步。这包括等待当前线程可以获取 LC。

    【讨论】:

    • 不清楚。那么,如果在一个线程的类初始化过程中,另一个线程将尝试访问其字段,会发生什么情况。会一直锁定到初始化完成吗?
    • @St.Antario,这就是诀窍。对象实例将在 Holder 类初始化期间创建,并且 Holder 类是非并发初始化的,这意味着第二个线程将等待 Holder 类初始化以及第一个线程。
    • 其实,明白了。这是我发现的一些formal jls explanation初始化 C 的过程如下:在 C 的初始化锁 LC 上同步。这包括等待当前线程可以获取 LC。如果您在答案中添加了一些正式的引用,对某人很有用。
    • 由于类初始化是非并发的,当初始化昂贵并且可以并行完成时,这也可能是一种反模式。
    猜你喜欢
    • 2014-11-25
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-07
    相关资源
    最近更新 更多