给定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
发布于 2009-05-12 03:23:09
好吧,除非您特别想在Java并发问题上与Brian Goetz意见相左,否则我认为这是错误的。虽然他的原话是“最好不要……”,但我还是听从了他的建议。来自JCIP,第42页:
“在构造期间可以让‘’引用转义的常见错误是从构造函数启动线程...在构造函数中创建线程没有什么问题,但最好不要立即启动线程。相反,公开一个或initialize方法...”
更新:只是为了详细说明为什么这是一个问题。尽管在对Thread.start()的调用和线程的run()方法实际开始执行之间肯定存在内存屏障,但是在调用Thread.start()之后构造函数期间发生的事情之间没有这种屏障。因此,如果还需要设置一些其他变量,或者如果JVM执行一些“刚刚构造的对象”的内务管理,那么这两个变量都不能保证被其他线程看到:即处于不完整状态的其他线程可以看到该对象。
顺便说一句,除了它是否真的破坏了JMM之外,它还让人感觉有点像构造函数中的一件“奇怪的事情”。
发布于 2009-05-11 22:55:17
JLS: Threads and Locks说
两个操作可以按发生之前的关系排序。如果一个动作发生在另一个动作之前,那么第一个动作对第二个动作是可见的,并且排序在第二个动作之前。
如果我们有两个动作x和y,我们写hb(x,y)来表明x发生在y之前。
和
对线程的start()调用发生在启动的线程中的任何操作之前。
因此,我们可以得出结论,在调用Thread.start()之前,构造函数中的所有操作都发生在启动的线程中的所有操作之前。如果Thread.start()毕竟是对对象字段的所有写操作,那么启动的线程将看到对对象字段的所有写操作。如果没有对字段的其他写入(另一个线程将读取),则代码是线程安全的。
发布于 2009-05-11 21:34:11
Runnable
https://stackoverflow.com/questions/850160
复制相似问题