Search code examples
javamultithreadingconcurrencysynchronizationvolatile

Is it any way to tell java threads to reload caches?


Studying some answers here about volatile keyword behavior I understood that targeting x86 architecture volatile reads are always happens from main memory which is quite expensive.

Consider next situation: I have a block of code that gets executed by lets say 3 threads. Something like that:

class Foo {
  private Bar bar;

  public Bar read () {
    return bar;
  }
  public void write(Bar bar) {
    this.bar = bar;
  }
}

And also I know that reads happen from 3 different threads every small amount of time (let's say 100ms) and write happens let's say once a year. To stick to a context consider Bar immutable - this question not covers interaction with this object, it's just about reference itself.

Making bar volatile will do it's task - each next read no matter which thread executes this read will end up with correct data. But it comes with a very high cost - each read would be the read from main memory.

UPD: So my question is next: is it any way on a JVM to avoid penalty of read from main memory? Maybe by making reference non volatile and telling threads that cached value may be not valid so this threads read from main memory only once a year but not every 100ms? Or at least make it cheaper than main ram read. Can it also be done in non-blocking fashion? Maybe there is a way to approach it using happens-before?


Solution

  • If you want your threads to normally reuse the previous value (even if it’s out of date) but occasionally check for updates, just do that:

    int hits=0;
    Bar cache=foo.read();  // Foo.bar is volatile
    while(/*...*/) {
      if(++hits==100) {
        hits=0;
        cache=foo.read();
      }
      cache.doStuff();
    }
    

    If you want to package this logic (because not all the lookups come from one function), add a layer of indirection and have a CountFoo per thread so that you aren’t sharing hit counters (or paying for thread-local storage).