有什么办法告诉Java线程重新加载缓存?

时间:2018-10-14 19:36:48

标签: java multithreading concurrency synchronization volatile

此处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

2 个答案:

答案 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 ;这允许在只读时没有锁定,而只有在有写入者时才具有(硬)锁定