这个引用转义单线程程序

时间:2013-06-01 21:53:51

标签: java concurrency

这个引用在构造问题期间(由Brian Goetz和其他人在Java Concurrency in Practice中调用)是否会影响单线程程序或只是多线程程序?我的意思是,如果我的类不应该是线程安全的,那么在构造期间让这个引用逃脱是否可以?

编辑:例如,在这里:

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            });
    }
}

EDIT2:我的问题的动机是Eclipse的插件WindowBuilder在JFrame的构造函数中创建(或似乎创建......)动作侦听器,并且默认情况下将匿名类传递给那些,从而允许此引用转义...

3 个答案:

答案 0 :(得分:3)

一般来说,在完全构造之前,不应该尝试使用对象。如果在完全初始化之前将对象传递给其他代码,这可能会导致混乱的结果,除非您非常小心。即使在单线程程序中也是如此。

那就是说,如果你知道直到以后才会使用该对象,有时它不是问题。

答案 1 :(得分:2)

允许“this”引用转义不一定会导致问题。它可以运行正常,但它完全取决于其他代码对它的作用。

那么为什么在构造函数中不泄漏它是最佳做法?如果EventSource立即从寄存器功能中发送“现在已连接”的事件,该怎么办?怎么了? doSomething()被调用(并且请注意,你仍然是构造函数的中间人,可能没有完成初始化对象)。它完全取决于方法的作用,但下列之一是正确的:

  1. doSomething中您需要的所有内容都会在注册侦听器之前进行初始化,并且可以解决问题。
  2. 某些东西是null,你忽略它,导致意想不到的结果
  3. 由于某些东西在它不应该是(NPE或类似的)时为空而被炸毁。
  4. 但是,你说,它不发送那个事件。所以你没事,对吧?好吧,在别人改变它之前,它开始发送类似的东西,然后你自发地破解而不直接改变你的代码。

    简短形式:如果可以,请避免这样做;它会导致头痛。如果你出于某种原因绝对必须这样做,那么在泄漏之前要小心你初始化你所能做的一切,并且要非常小心地了解将要发生的事情,并意识到未来可能会遇到麻烦。

答案 2 :(得分:1)

不要这样做。在构造之前让引用转义可能导致未指定的行为。使用静态工厂模式,让你的烦恼休息,多线程或不是

在您的示例中,它看起来像这样:

public class ThisEscape{
  private final EventListener listener;

  private ThisEscape(){
    listener = new EventListener();
  }

  public static public ThisEscape makeEscape(EventSource source){
    ThisEscape e = new ThisEscape();
    source.registerListener(e.listener);
    return e;
  }

  private class EventListener{
    public void onEvent(Event e){
      doSomething(e);
    }
  }
}

显然静态工厂不允许无级扩展,但根据我的经验,这通常不是问题,即使需要制作一些工厂方法。

此代码在构造方面是线程安全的;一定要注意你班上的其他人都是线程安全的。