我一直在寻找为什么不应该在类的构造函数中调用线程的 start 方法的理由。考虑以下代码:
class SomeClass
{
public ImportantData data = null;
public Thread t = null;
public SomeClass(ImportantData d)
{
t = new MyOperationThread();
// t.start(); // Footnote 1
data = d;
t.start(); // Footnote 2
}
}
ImportantData 是一些通用的东西(可能很重要),而 MyOperationThread 是线程的子类,它知道如何处理 SomeClass 实例。
脚节点:
我完全理解为什么这是不安全的。如果 MyOperationThread 在以下语句完成之前尝试访问 SomeClass.data (并且数据已初始化),我将得到一个我没有准备好的异常。或者也许我不会。你不能总是用线程来判断。在任何情况下,我都会为以后奇怪的、意想不到的行为做好准备。
我不明白为什么这样做是禁地。至此,SomeClass的所有成员都已经初始化完毕,没有调用其他改变状态的成员函数,构建就有效完成了。
据我了解,这样做被认为是不好的做法的原因是您可以“泄漏对尚未完全构造的对象的引用”。但是对象已经完全构造好了,构造函数只好返回了。我搜索了其他问题以寻找更具体的答案,并查看了参考资料,但没有找到任何说“你不应该因为这样那样的不良行为”的东西,只有那些说“你不应该。”
在构造函数中启动线程在概念上与这种情况有何不同:
class SomeClass
{
public ImportantData data = null;
public SomeClass(ImportantData d)
{
// OtherClass.someExternalOperation(this); // Not a good idea
data = d;
OtherClass.someExternalOperation(this); // Usually accepted as OK
}
}
顺便说一句,如果课程是最后的怎么办?
final class SomeClass // like this
{
...
我看到很多关于这个的问题和你不应该回答的问题,但没有一个提供解释,所以我想我会尝试添加一个包含更多细节的问题。