这个引用在构造问题期间(由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的构造函数中创建(或似乎创建......)动作侦听器,并且默认情况下将匿名类传递给那些,从而允许此引用转义...
答案 0 :(得分:3)
一般来说,在完全构造之前,不应该尝试使用对象。如果在完全初始化之前将对象传递给其他代码,这可能会导致混乱的结果,除非您非常小心。即使在单线程程序中也是如此。
那就是说,如果你知道直到以后才会使用该对象,有时它不是问题。
答案 1 :(得分:2)
允许“this”引用转义不一定会导致问题。它可以运行正常,但它完全取决于其他代码对它的作用。
那么为什么在构造函数中不泄漏它是最佳做法?如果EventSource立即从寄存器功能中发送“现在已连接”的事件,该怎么办?怎么了? doSomething()被调用(并且请注意,你仍然是构造函数的中间人,可能没有完成初始化对象)。它完全取决于方法的作用,但下列之一是正确的:
但是,你说,它不发送那个事件。所以你没事,对吧?好吧,在别人改变它之前,它开始发送类似的东西,然后你自发地破解而不直接改变你的代码。
简短形式:如果可以,请避免这样做;它会导致头痛。如果你出于某种原因绝对必须这样做,那么在泄漏之前要小心你初始化你所能做的一切,并且要非常小心地了解将要发生的事情,并意识到未来可能会遇到麻烦。
答案 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);
}
}
}
显然静态工厂不允许无级扩展,但根据我的经验,这通常不是问题,即使需要制作一些工厂方法。
此代码在构造方面是线程安全的;一定要注意你班上的其他人都是线程安全的。