通过决赛安全发布

dev*_*ull 4 java

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

and*_*soj 9

编辑补充:有趣的观点来看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也能保证看到写入listener = new EventListener()....如果该字段不是final,您将无法获得该保证.有几种(其他)方式提供不同性能和可读性的保证(显式同步,使用原子引用,使用易失性).

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

最近一个相关的问题是:"内存障碍和编码......","Java多线程和安全发布".


Thi*_*ilo 5

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

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

这是 JVM 规范的一部分。

它是如何工作的将是一个 JVM 实现细节。