通过决赛安全发布

即使经过这个 ,我仍然不清楚最终的使用如何导致安全发布在下面的代码中。 有人能给出一个易于理解的解释。

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; } } 

编辑补充:有趣的观点来看Java和JSR-133的final行为 。

关于final如何在新JMM中工作的规范参考,安全发布: http : //www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRight

简单回顾一下,我认为你的代码代表了对EventSource source对象的“安全”发布,它可能会在不同的线程中向listener事件回调。 保证在传递的safe.listener引用上运行的线程将看到完全初始化的listener字段。 这不会进一步保证与调用onEvent或与对象状态的其他交互相关的其他同步问题。

您的代码保证的是,当SafeListener的构造函数在静态方法中返回引用时, listener字段将不会在未写入状态下被看到(即使没有显式同步)。 例如:假设线程A调用newInstance() ,从而导致对listener字段的赋值。 假设线程B能够取消引用listener字段。 然后,即使没有任何其他同步,线程B也能保证看到write listener = new EventListener()... 如果该领域不是final ,您将无法获得该保证。 有几种(其他)方式提供不同性能和可读性的保证(显式同步,使用primefaces引用,使用易失性)。

并非所有合法的都是可取的。 建议你看看JCiP ,或许这篇关于安全发布技术的文章 。

最近一个相关的问题是: “内存障碍和编码……” , “Javamultithreading和安全发布” 。

简而言之, final的规范(参见@ andersoj的答案)保证当构造函数返回时,最终字段将被正确初始化(从所有线程可见)。

对于非最终字段没有这样的保证(这意味着如果另一个线程获得新构造的对象,则该字段可能尚未设置)。

这有效是JVM规范的一部分。

它的工作原理是JVM实现细节。

您可以引用JSL Final字段,或者通过最终引用可访问的对象不能在初始加载对该对象的引用时重新排序。 在构造之后,所有其他线程都可以看到它。