Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

thread safe without volatile

Can anyone explain why this example is thread safe without volatile?

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

In fact, assuming that the computeHashCode function always returned the same result and had no side effects (i.e., idempotent), you could even get rid of all of the synchronization.

// Lazy initialization 32-bit primitives
// Thread-safe if computeHashCode is idempotent
class Foo { 
  private int cachedHashCode = 0;
  public int hashCode() {
    int h = cachedHashCode;
    if (h == 0) {
      h = computeHashCode();
      cachedHashCode = h;
      }
    return h;
    }
  // other functions and members...
  }

MORE: I get it, we don't care if the value is computed twice (so it is not truly thread safe). I also like to know if new threads created after the hashcode has been calculated is guaranteed to see the new hashcode?

like image 224
Stig Avatar asked Dec 04 '22 05:12

Stig


1 Answers

This is walking on a thin ice, but here is the explanation. Visibility problem means that some threads might see old version and some - new one. In our case, some threads see 0 while others - cachedHashCode.

Threads that call hashCode() and see cachedHashCode will just return it (if (h == 0) condition is not met) and everything works.

But threads that see 0 (despite the cachedHashCode might have already been computed) will just recompute it again.

In other words, in the worst case scenario, every thread will enter the branch seeing 0 for the first time (like if it was ThreadLocal).

Since computeHashCode() is idempotent (very important), both calling it several times (by different threads) and reassign it again to the same variable shouldn't have any side effects.

like image 174
Tomasz Nurkiewicz Avatar answered Dec 09 '22 16:12

Tomasz Nurkiewicz