我可以从构造函数中启动一个线程吗?

时间:2009-05-11 21:26:12

标签: java multithreading

鉴于J5 +内存模型(JSR-133)是以下代码线程安全且允许的吗?

如果它是安全的,在某些情况下是否可以接受?

public final class BackgroundProcessor
extends Object
implements Runnable
{

public BackgroundProcessor(...) {
    super();

    ...

    new Thread(this).start();
    }

public void run() {
    ...
    }
}

当我阅读新的JMM规范时,启动一个线程会创建一个与发起的线程所做的事情之前发生的关系。

假设对象在构造函数中设置了私有成员变量,并在run()中使用。

该课程被标记为最终,以防止出现分类意外。

注意:这里有一个类似的问题,但这有一个不同的角度:calling thread.start() within its own constructor

3 个答案:

答案 0 :(得分:4)

JLS: Threads and Locks

  

可以通过先发生关系来排序两个动作。如果一个动作发生在另一个动作之前,则第一个动作在第二个动作之前可见并且在第二个之前被命令。

     

如果我们有两个动作x和y,我们写hb(x,y)来表示x发生在y之前。

     
      
  • 如果x和y是同一个线程的动作,并且x在程序顺序中位于y之前,那么hb(x,y)。
  •   

  

在启动线程中的任何操作之前,对线程的start()调用发生。

因此我们可以得出结论,在调用Thread.start()之前,构造函数中的所有操作都发生在启动的线程中的所有操作之前。如果Thread.start()完全写入对象的字段后,则启动的线程将看到对对象字段的所有写入。如果没有其他字段写入(另一个线程将读取),则代码是线程安全的。

答案 1 :(得分:3)

好吧,除非你特别想在Brian并发问题上不同意Brian Goetz,否则我认为这是错误的。虽然他的确切言论是“最好不要......”,但我仍然听从了他的建议。来自 JCIP,p。 42:

  

常见错误,可以让...   '这个'参考逃脱期间   构建是开始一个线程   来自构造函数 [...]有   创建一个线程没有错   在构造函数中,但最好不要   立即启动线程。   相反,暴露一个开始或初始化   方法...“

更新:只是为了详细说明这是一个问题。尽管在调用Thread.start()和该线程的run()方法实际开始执行之间存在内存障碍,但在调用之后构造函数中发生的事情之间没有这样的障碍。 Thread.start()。因此,如果仍然要设置一些其他变量,或者如果JVM执行一些“刚刚构造的对象”内务处理,则其他线程都不会保证这些变量看不到:即该对象可以被处于不完整状态的其他线程。

顺便说一句,除了它是否真的打破了JMM之外,它在构造函数中感觉有点像“奇怪的事情”。

答案 2 :(得分:-3)

  1. 您的课程可能应该实现Runnable

  2. 是的,您的代码没问题

  3. 扩展Object并不是一件好事。我确信你知道所有类都隐式扩展了Object。我不知道明确扩展对象的流行做法来自哪里,但这是一种不好的风格。