鉴于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
答案 0 :(得分:4)
可以通过先发生关系来排序两个动作。如果一个动作发生在另一个动作之前,则第一个动作在第二个动作之前可见并且在第二个之前被命令。
如果我们有两个动作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)
您的课程可能应该实现Runnable
是的,您的代码没问题
扩展Object并不是一件好事。我确信你知道所有类都隐式扩展了Object。我不知道明确扩展对象的流行做法来自哪里,但这是一种不好的风格。