Den*_*nov 13 java concurrency volatile
假设我有以下代码
private volatile Service service;
public void setService(Service service) {
this.service = service;
}
public void doWork() {
service.doWork();
}
Run Code Online (Sandbox Code Playgroud)
修改后的字段标记为volatile,其值不依赖于先前的状态.所以,这是正确的多线程代码(不用担心Service一分钟的实现).
据我所知,从内存可见性的角度来看,读取volatile变量就像输入一个锁.这是因为读取常规变量不能通过读取volatile变量来重新排序.
这是否意味着以下代码是正确的?
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();
}
}
Run Code Online (Sandbox Code Playgroud)
Cow*_*wan 18
是的,从Java 1.5开始,这段代码是"正确的".
原子性不是一个问题,有或没有volatile(写入对象引用是原子的),所以你可以通过任何方式跨越关注列表 - 唯一的开放问题是变化的可见性和排序的'正确性'.
对volatile变量的任何写入都会建立一个'发生在'之前的关系(新的Java内存模型的关键概念,如JSR-133中所指定的)以及对同一变量的任何后续读取.这意味着读取线程必须能够看到写入线程可见的所有内容:也就是说,它必须在写入时查看至少具有"当前"值的所有变量.
我们可以通过查看Java语言规范的第17.4.5节详细解释这一点,特别是以下要点:
所以在你的例子中:
这意味着,一旦serviceReady为true,就可以保证正确设置'service'.
您可以使用几乎完全相同的示例(IBM DeveloperWorks中的一个示例)看到一些好的文章- 请参阅"新保证的易失性":
现在保证在写入V时A可见的值对B可见.
JSR-133 FAQ中的一个,由JSR的作者撰写:
因此,如果读者看到v的值为true,那么也可以保证看到在它之前发生的写入42.在旧的内存模型下,这不可能是真的.如果v不是volatile,那么编译器可以重新排序writer中的写入,读者对x的读取可能会看到0.
| 归档时间: |
|
| 查看次数: |
1892 次 |
| 最近记录: |