发生在与Java中的易失性字段和同步块的关系之前 - 以及它们对非易失性变量的影响? [英] Happens-before relationships with volatile fields and synchronized blocks in Java - and their impact on non-volatile variables?

查看:109
本文介绍了发生在与Java中的易失性字段和同步块的关系之前 - 以及它们对非易失性变量的影响?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我仍然对线程的概念很陌生,并尝试更多地了解它。最近,我发现了一篇关于什么挥发的博客文章由杰里米·曼森撰写的Java中的手段,他写道:

I am still pretty new to the concept of threading, and try to understand more about it. Recently, I came across a blog post on What Volatile Means in Java by Jeremy Manson, where he writes:


当一个线程写入一个volatile变量,另一个线程看到
写入,第一个线程告诉第二个关于内存的
内容的全部,直到它执行对该volatile
变量的写入。 [...] 所有线程1看到的内存内容,在写入 [volatile] ready
之前,必须是在线程2可见之后,
ready 读取值 true 。 [我自己强调]

When one thread writes to a volatile variable, and another thread sees that write, the first thread is telling the second about all of the contents of memory up until it performed the write to that volatile variable. [...] all of the memory contents seen by Thread 1, before it wrote to [volatile] ready, must be visible to Thread 2, after it reads the value true for ready. [emphasis added by myself]

现在,这是否意味着当时线程1内存中保存的所有变量(易失性或非易失性)在读取volatile变量后,对volatile 2变量的写入将变为可见吗?如果是这样, 是否可以从官方Java文档/ Oracle源代码中将该语句拼凑起来?从哪个版本的Java开始工作?

Now, does that mean that all variables (volatile or not) held in Thread 1's memory at the time of the write to the volatile variable will become visible to Thread 2 after it reads that volatile variable? If so, is it possible to puzzle that statement together from the official Java documentation/Oracle sources? And from which version of Java onwards will this work?

特别是,如果所有线程共享以下类变量:

In particular, if all Threads share the following class variables:

private String s = "running";
private volatile boolean b = false;

线程1首先执行以下操作:

And Thread 1 executes the following first:

s = "done";
b = true;

然后线程2执行(在线程1写入volatile字段后):

And Thread 2 then executes afterwards (after Thread 1 wrote to the volatile field):

boolean flag = b; //read from volatile
System.out.println(s);

这可以保证打印完成吗?

Would this be guaranteed to print "done"?

如果不是将 b 声明为 volatile ,我会发生什么?并读入 synchronized 块?

What would happen if instead of declaring b as volatile I put the write and read into a synchronized block?

此外,在题为 线程之间是否共享静态变量?,@ TREE 写作

Additionally, in a discussion entitled "Are static variables shared between threads?", @TREE writes:


不要使用volatile来保护多个共享状态。

Don't use volatile to protect more than one piece of shared state.

为什么? (对不起;我还不能就其他问题发表评论,或者我会问那里......)

Why? (Sorry; I can't comment yet on other questions, or I would have asked there...)

推荐答案

是的,保证线程2将打印完成。当然,如果在线程1中写入 b 实际发生在线程2中从 b 读取之前,而不是在同一时间或之前发生!

Yes, it is guaranteed that thread 2 will print "done" . Of course, that is if the write to b in Thread 1 actually happens before the read from b in Thread 2, rather than happening at the same time, or earlier!

这里推理的核心是 happens-before relationship 。多线程程序执行被视为由事件组成。事件可以通过发生在之前的关系来关联,这表示一个事件发生在另一个事件之前。即使两个事件没有直接关联,如果你可以追踪从一个事件到另一个事件的一系列发生前的关系,那么你可以说一个事件发生在另一个事件之前。

The heart of the reasoning here is the happens-before relationship. Multithreaded program executions are seen as being made of events. Events can be related by happens-before relationships, which say that one event happens before another. Even if two events are not directly related, if you can trace a chain of happens-before relationships from one event to another, then you can say that one happens before the other.

在您的情况下,您有以下事件:

In your case, you have the following events:


  • 线程1写入 s

  • 线程1写入 b

  • 线程2从<$ c $读取c> b

  • 线程2从 s读取

  • Thread 1 writes to s
  • Thread 1 writes to b
  • Thread 2 reads from b
  • Thread 2 reads from s

以下规则发挥作用:


  • 如果x和y是行动相同的线程和x在程序顺序中出现在y之前,然后是hb(x,y)。 (程序顺序规则)

  • 在对该字段的每次后续读取之前发生对易失性字段(第8.3.1.4节)的写入。 ( volatile 规则)

  • "If x and y are actions of the same thread and x comes before y in program order, then hb(x, y)." (the program order rule)
  • "A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field." (the volatile rule)

以下情况发生 - 因此存在关系:

The following happens-before relationships therefore exist:


  • 线程1写入 s 线程1写入之前发生 b (程序订单规则)

  • 线程1写入 b 线程2从 b (易变规则)读取之前发生

  • 线程2从 b 读取线程2从 s读取 (程序订单规则)

  • Thread 1 writes to s happens before Thread 1 writes to b (program order rule)
  • Thread 1 writes to b happens before Thread 2 reads from b (volatile rule)
  • Thread 2 reads from b happens before Thread 2 reads from s (program order rule)

如果您关注该链,您可以看到结果:

If you follow that chain, you can see that as a result:


  • 线程1写入 s 发生在线程2读取之前来自 s

这篇关于发生在与Java中的易失性字段和同步块的关系之前 - 以及它们对非易失性变量的影响?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆