跨线程的对象可见性

时间:2009-05-03 18:41:21

标签: java concurrency

我对跨线程发布数据和数据更改存在一般性疑问。 例如考虑以下类。

public class DataRace {
  static int a = 0;

  public static void main() {
    new MyThread().start();
    a = 1;
  }

  public static class MyThread extends Thread {
    public void run() { 
      // Access a, b.
    }
  }
}

让我们关注main()。

显然

new MyThread().start();
a = 1;

我们在MyThread启动后更改共享变量a,因此可能不是线程安全的发布。

a = 1;
new MyThread().start();

然而,这次a的更改是通过新线程安全发布的,因为Java语言规范(JLS)保证线程A在启动线程B时可见的所有变量对线程B可见,这是实际上就像在Thread.start()中有一个隐式同步。

new MyThread().start();
int b = 1;

在这种情况下,在生成两个线程之后分配新变量时,是否可以保证新变量将安全地发布到所有线程。即如果var b被另一个线程访问,它是否保证看到它的值为1.请注意,我之前没有讨论对b的任何后续修改(当然需要同步),但是第一次完成分配由jvm。

谢谢,

6 个答案:

答案 0 :(得分:5)

我对这一点并不完全确定:

a = 1;
new MyThread().start();

...因为我不确定在新线程启动之前是否保证a的值会被“刷新”到共享内存。但是,该规范明确地谈到了这一点。在section 17.4.4中声明:

  

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

(之后的讨论基本上表明它会没问题。)

我不确定你的最后一个例子(b)是什么意思。

答案 1 :(得分:1)

我不确定你在这里问的是什么。我认为你在谈论对“a”变量的线程安全访问。

问题不是调用的顺序,而是

的事实

-access to a不是线程安全的。因此,在多个线程更新和读取a的示例中,您将永远无法保证您正在读取的“a”与您更新的值相同(某些其他线程可能已更改该值)。

- 在多线程环境中,jvm不保证a的更新值保持同步。例如。

Thread 1: a=1

Thread 2: a=2

Thread 1: print a <- may return 1

您可以通过声明“易变”来避免这种情况。

如上所述,根本没有任何关于a。

的价值的保证 BTW,Josh Bloch的Concurrency in Practice是关于这个主题的伟大的书(我说它还没有完全通过它;) - 这真的帮助我理解了如何处理线程问题。

答案 2 :(得分:0)

a = 1;
new MyThread().start();

在新线程上调用start之前将发生对'a'的赋值,因此新线程将始终打印值'1'

new MyThread().start();
a = 1;

在这种情况下,MyThread可以打印1或0作为'a'的值。

答案 3 :(得分:0)

MyThread()。start()启动一个单独运行的新线程。 int b = 1的声明与您启动的线程无关。它继续在主线程中。

如果两个线程同时读取或改变同一个Object,或者如果两个线程以相反的顺序获取资源上的锁,那么线程安全就是一个问题,因此每个线程都在等待另一个线程(这称为死锁) )。

答案 4 :(得分:0)

我怀疑这个问题:)

有关在并发执行线程之间访问共享资源的问题是一个相当容易理解和调查的主题。

通常,如果您有一个通过多个线程使用读/写语义访问的源,则需要管理对该资源的访问。 (这里的资源是静态int变量DataRace.a)

(我也在这里给Steve B.注意,这里的问题不是调用的顺序。)

答案 5 :(得分:0)

如果b是在DataRace.main()中创建的局部变量,如代码片段所示,MyThread无法访问它,所以问题没有实际意义。

如果b是主线程和MyThread线程之间的共享变量,则在没有适当的内存屏障的情况下它没有正确的可见性,因此MyThread可能无法及时看到正确的值。