此处some研究answers about易失性关键字行为我了解,针对x86体系结构的易失性读取总是总是发生在主存储器上,这非常昂贵。 / p>
考虑下一种情况: 我有一个代码块,可以说3个线程执行。像这样:
class Foo {
private Bar bar;
public Bar read () {
return bar;
}
public void write(Bar bar) {
this.bar = bar;
}
}
我也知道,每隔很少的时间(比如说100毫秒)就会从3个不同的线程中进行读取,而写操作则是每年一次。坚持上下文,认为Bar是不可变的-这个问题不涉及与该对象的交互,而只是参考本身。
使bar变为volatile将完成其任务-每次下一次读取,无论哪个线程执行此读取都将得到正确的数据。但这会带来很高的成本-每次读取都是从主内存读取。
UPD :所以我的下一个问题是:在JVM上是否可以避免从主内存读取的损失?也许通过使引用变为非易失性并告诉线程缓存的值可能无效,因此该线程每年仅从主存储器读取一次,而不是每100ms读取一次?或者至少使其比main ram read便宜。还能以非阻塞方式完成吗?也许有一种方法可以使用 happens-before ?
答案 0 :(得分:1)
如果您希望线程正常重用以前的值(即使它已经过时),但偶尔检查更新,只需执行以下操作:
int hits=0;
Bar cache=foo.read(); // Foo.bar is volatile
while(/*...*/) {
if(++hits==100) {
hits=0;
cache=foo.read();
}
cache.doStuff();
}
如果您要打包此逻辑(因为并非所有查找都来自一个函数),请添加一个间接层并为每个线程添加CountFoo
,这样您就不必共享点击计数器(或为线程本地存储付费)。
答案 1 :(得分:0)
使用rw_locks 参见http://tutorials.jenkov.com/java-concurrency/read-write-locks.html ;这允许在只读时没有锁定,而只有在有写入者时才具有(硬)锁定