java - Java 中私有(private)构造函数如何实现发布安全

标签 java multithreading constructor thread-safety safe-publication

在经典的《Java 并发实践》中,Brian Goetz 使用以下代码片段演示了如何使用私有(private)构造函数和工厂方法安全地发布对象:

public class SafeListener {
    private final EventListener listener;

    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        };
    }

    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

我还不明白的是这段代码如何通过私有(private)构造函数实现安全发布。

我知道私有(private)构造函数用于防止在对象外部实例化,但这如何应用于线程而不是对象?线程不一定是对象,我可以'在构造函数完成执行之前,看看是什么阻止另一个线程获取对 safe 的引用。

最佳答案

构造函数的私有(private)属性与线程安全无关。这是最终现场发布保证的示例。为了使其工作,final 字段的 this 实例不得在构造函数期间转义,因此工厂方法负责构造首先持有者实例,然后注册监听器。然后。工厂模式的应用程序很自然地具有私有(private)构造函数和公共(public)工厂方法,但这对于实现线程安全并不重要。

这都是关于 JIT 和 HotSpot 优化器在执行优化时如何处理代码的。他们知道什么是finalvolatile 字段以及什么是构造函数。他们将遵守此类构造的优化程度的限制。最重要的是,它们确保对存储在 final 字段中的对象的所有写入以及对 final 字段本身的写入发生在之前构造函数结束,以便 final 字段存储示例中 registerListener 调用发生的任何效果。因此,在正确初始化之前,其他线程无法看到监听器引用。

请注意,这是您很少应该依赖的东西。在您的示例中,如果 EventSource 的方法 registerListener 不是线程安全的,仍然可能会发生非常糟糕的事情。另一方面,如果它是线程安全的,那么它的线程安全性也将应用于注册之前构造的监听器,因此不需要 final 字段保证。

关于java - Java 中私有(private)构造函数如何实现发布安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21548511/

相关文章:

java - 尽管满足条件,while 循环仍不循环

java - Flex 或 Actionscript 中的 Java 语法荧光笔

c++ - 如果没有语句,While 循环不检查条件

c++ - 使用 C++ 可变参数模板通过类构造函数传递数组

java - 这段代码是某种命令模式吗?

java - 使用正则表达式获取子字符串

scala - 在类构造函数中使用特征方法

c++ - 复制构造函数的问题

c# - BeginFlush 似乎同步工作

ios - 重新路由期间Skobbler API的问题