在经典的《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 优化器在执行优化时如何处理代码的。他们知道什么是final
或volatile
字段以及什么是构造函数。他们将遵守此类构造的优化程度的限制。最重要的是,它们确保对存储在 final
字段中的对象的所有写入以及对 final
字段本身的写入发生在之前构造函数结束,以便 final
字段存储示例中 registerListener
调用发生的任何效果。因此,在正确初始化之前,其他线程无法看到监听器引用。
请注意,这是您很少应该依赖的东西。在您的示例中,如果 EventSource
的方法 registerListener
不是线程安全的,仍然可能会发生非常糟糕的事情。另一方面,如果它是线程安全的,那么它的线程安全性也将应用于注册之前构造的监听器,因此不需要 final
字段保证。
关于java - Java 中私有(private)构造函数如何实现发布安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21548511/