安全发布:第一次将Object引用传递给另一个线程需要安全发布的习语吗?

时间:2011-05-30 05:45:00

标签: java

我有一个C类,定义如下:

public Class C implements Runnable
{
    private B ref;
    public C(B bobj)
    {
    this.ref = bobj;                 //(0)
    }
}    

public void run()
{
    //read ‘ref’ without using synchronization.  //(4)
    //Will this read of ref see an up-to-date value or stale (may be null) value?
    //do some stuff on ‘ref’ using lock ‘ref’   
}
}

我有一个已经运行的线程T(例如主线程)。 线程T创建另一个类B(可变)的实例,例如

B b = new B();

现在它构造了一个C类实例并启动了Thread,例如

C runnable = new C(b);                          // (1)
new Thread(runnable).start();     //(2)

根据Java语言规范17.4.4:

  

启动线程的操作与线程中的第一个操作同步   启动。

=>上述声明(2)与声明(4)同步。

同一规范17.4.5的下一部分说:

  

如果动作x与后续动作y同步,那么我们也有hb(x,   Y)。

=>这里声明(2)发生在声明之前(4)

此外,语句(2)之前的语句(1)无法重新排序(否则C的run()中的代码可能会被编译器检测到)(1)在程序顺序之前(2) (线程内语义)。这意味着,声明(1)将在执行顺序之前(4)。

我的问题是这种将引用(这里是'b')从一个线程传递到另一个线程的方式是否安全?

1 个答案:

答案 0 :(得分:0)

在这种情况下是安全的。

B b = new B();
C runnable = new C(b);
new Thread(runnable).start();

上面的代码保证B被构造并传递给C,并且它是安全的等等。你不能保证的是任何后期修改,例如

new Thread(runnable).start();
b.setSomeStuff(new Stuff());

在针对线程代码运行时:

public void run() {
  Stuff stuff = b.getSomeStuff(); // Can return old or new stuff.
}

有效地,为了回答你的问题,C不能运行,除非它是完全构造的,这需要B存在并且能够被引用。只有当你修改一个线程中的东西并在两个线程都在运行时在另一个线程中读取它时才会出现问题。