相对于其他字段的易失语义 [英] Volatile semantic with respect to other fields

查看:110
本文介绍了相对于其他字段的易失语义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下代码:

  

public void setService(Service service){
this.service = service;
}

public void doWork(){
service.doWork();
}

修改的字段标记为volatile,其值不依赖于之前的状态。所以,这是正确的多线程代码(不用担心 Service 一分钟)。



如我所知,读取volatile变量就像进入一个锁,从内存可见性的角度。这是因为正常变量的读取不能通过读取volatile变量重新排序。



这是否意味着下面的代码是正确的?

  private volatile boolean serviceReady = false; 
私人服务;

public void setService(Service service){
this.service = service;
this.serviceReady = true;
}

public void doWork(){
if(serviceReady){
service.doWork();
}
}


解决方案

是,这个代码从Java 1.5开始是正确的。



原子性不是一个问题,有或没有volatile(对对象引用的写入是原子的) ,所以你可以跨越那些关注列表的方式 - 唯一的开放问题是变化的可见性和排序的正确性。



任何写入volatile变量设置了一个happens-before关系(新的Java内存模型的关键概念,如 JSR-133 )与同一变量的任何后续读取。这意味着读取线程必须能够看到写线程可见的所有内容:也就是说,它必须在写入时看到所有具有至少其当前值的变量。



我们可以通过查看 Java语言规范的第17.4.5节,特别是以下要点:


  1. 如果x和y是同一个线程的动作,而x以程序顺序出现在y之前,那么hb(x,y)(也就是说,同一线程上的动作不能以不一致的方式重新排序)程序顺序)

  2. 对易失性字段(§8.3.1.4)的写入发生在该字段的每次后续读取之前。 (这是澄清文本,解释易失性字段的写入然后读取是同步点)

  3. 如果hb(x,y)和hb(y,z) hb(x,z)(happens-before的传递性)

在您的示例中:


由于规则1,在写入'serviceReady'(b)之前,写入'service'(a)


  • 因为规则2

  • ,在读取相同(c)之前写入'serviceReady'(b) )



这意味着您可以确保在serviceReady为true时,service被正确设置。

您可以使用完全相同的示例查看一些好的写作, IBM DeveloperWorks - 请参阅Volatile的新保证:

$ b $


一个在 JSR-133常见问题< a>,由JSR的作者写的:


因此,如果读者看到v的值为true,看到写在42之前发生了。这在旧的内存模型下不会是真的。如果v不是volatile,那么编译器可以重新排序写入器中的写入,读取器读取的x可能看到0。



Suppose I have following code

private volatile Service service;

public void setService(Service service) {
  this.service = service;
}

public void doWork() {
  service.doWork();
}

Modified field marked as volatile and its value do not depend on previous state. So, this is correct multithreaded code (don't bother about Service implementations for a minute).

As far as I know, reading volatile variable is like entering a lock, from perspective of memory visibility. It's because reading of normal variables can not be reordered with reading volatile variables.

Does this mean that following code is correct?

private volatile boolean serviceReady = false;
private Service service;

public void setService(Service service) {
  this.service = service;
  this.serviceReady = true;
}

public void doWork() {
  if ( serviceReady ) {
    service.doWork();
  }
}

解决方案

Yes, this code is 'correct' as it stands, from Java 1.5 onwards.

Atomicity is not a concern, with or without the volatile (writes to object references are atomic), so you can cross that off the concerns list either way -- the only open question is visibility of changes and the 'correctness' of the ordering.

Any write to a volatile variable sets up a 'happens-before' relationship (the key concept of the new Java Memory Model, as specified in JSR-133) with any subsequent reads of the same variable. This means that the reading thread must have visibility into everything visible to the writing thread: that is, it must see all variables with at least their 'current' values at the time of the write.

We can explain this in detail by looking at section 17.4.5 of the Java Language Specification, specifically the following key points:

  1. "If x and y are actions of the same thread and x comes before y in program order, then hb(x, y)" (that is, actions on the same thread cannot be reordered in a way to be inconsistent with program order)
  2. "A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field." (this is clarifying text, explaining that write-then-read of a volatile field is a synchronization point)
  3. "If hb(x, y) and hb(y, z), then hb(x, z)" (transitivity of happens-before)

So in your example:

  • the write to 'service' (a) happens-before the write to 'serviceReady' (b), due to rule 1
  • the write to 'serviceReady' (b) happens-before the read of same (c), due to rule 2
  • therefore, (a) happens-before (c) (3rd rule)

meaning that you are guaranteed that 'service' is set correctly, in this instance, once serviceReady is true.

You can see some good write-ups using almost exactly the same example, one at IBM DeveloperWorks -- see "New Guarantees for Volatile":

values that were visible to A at the time that V was written are guaranteed now to be visible to B.

and one at the JSR-133 FAQ, written by the authors of that JSR:

Thus, if the reader sees the value true for v, it is also guaranteed to see the write to 42 that happened before it. This would not have been true under the old memory model. If v were not volatile, then the compiler could reorder the writes in writer, and reader's read of x might see 0.

这篇关于相对于其他字段的易失语义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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