可能的重复:
Java:为什么不在构造函数中启动线程?如何终止?
我习惯了跑步FindBugs在我的代码上,以便发现错误或不良做法。
今天它抱怨我在类构造函数中启动一个线程。
真的是一件坏事吗?你能解释一下为什么吗?
如果我的课是期末考试至少是安全的吧?
EDIT:
该线程作为内部类实现,并且仅使用启动时已初始化的主类的字段:
public final class SingletonOuter {
private static SingletonOuter ourInstance = new SingletonOuter();
public static SingletonOuter getInstance() {
return ourInstance;
}
private final SomeOtherClass aField;
private SingletonOuter() {
aField=new SomeOtherClass();
thread=new InnerThread();
thread.start();
}
private boolean pleaseStop;
private synchronized boolean askedStop(){return pleaseStop;}
public synchronized void stop(){
pleaseStop=true;
}
private final InnerThread thread ;
private class InnerThread extends Thread{
@Override public void run() {
//do stuff with aField until askedStop()
}
}
}
EDIT:
我最终将线程的启动移至 getInstance 方法,以避免引入未来错误的可能性:
public final class SingletonOuter {
private static SingletonOuter ourInstance
public static SingletonOuter getInstance() {
if (ourInstance==null){
ourInstance= = new SingletonOuter();
ourInstance.thread.start();
}
return ourInstance;
}
private final SomeOtherClass aField;
private SingletonOuter() {
aField=new SomeOtherClass();
thread=new InnerThread();
}
...
为什么在构造函数上创建新线程是不好的做法?
Findbugs 警告您有关对象构造的指令重新排序可能性的问题。尽管为新对象分配了内存空间,但不能保证在您创建对象时任何字段都已初始化。InnerThread
已经开始了。虽然final
fields will在构造函数完成之前初始化,不能保证如果InnerThread
开始使用(例如)aField
当它启动时,它将被初始化。 Java 编译器这样做是出于性能方面的考虑。它还可以选择将非最终字段的初始化移至after新实例已由构造函数返回。
如果您在构造函数中启动一个新线程,则该线程有可能处理部分初始化的对象。即使thread.start()
是构造函数中的最后一个语句,由于重新排序,新线程可能正在访问部分构造的对象。这是 Java 语言规范的一部分。
这是关于该主题的一个很好的链接:在自己的构造函数中调用 thread.start()
它提到以下内容:
通过从构造函数内启动它,您肯定会违反 Java 内存模型指南。看Brian Goetz 的安全施工技术了解更多信息。
Edit:
由于您的代码正在启动一个正在访问的新线程afield
,根据Java内存模型无法保证afield
当线程开始运行时将被正确初始化。
我建议改为添加一个start()
类上调用的方法thread.start()
。这是一种更好的做法,并且使使用此类的其他类更清楚地看到在构造函数中创建了线程。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)