Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't we need volatile with StampedLock?

Given a code sample from Oracle docs https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/StampedLock.html

class Point {
   private double x, y;
   private final StampedLock sl = new StampedLock();

   void move(double deltaX, double deltaY) { // an exclusively locked method
     long stamp = sl.writeLock();
     try {
       x += deltaX;
       y += deltaY;
     } finally {
       sl.unlockWrite(stamp);
     }
   }

   double distanceFromOrigin() { // A read-only method
     long stamp = sl.tryOptimisticRead();
     double currentX = x, currentY = y;
     if (!sl.validate(stamp)) {
        stamp = sl.readLock();
        try {
          currentX = x;
          currentY = y;
        } finally {
           sl.unlockRead(stamp);
        }
     }
     return Math.sqrt(currentX * currentX + currentY * currentY);
   }

   void moveIfAtOrigin(double newX, double newY) { // upgrade
     // Could instead start with optimistic, not read mode
     long stamp = sl.readLock();
     try {
       while (x == 0.0 && y == 0.0) {
         long ws = sl.tryConvertToWriteLock(stamp);
         if (ws != 0L) {
           stamp = ws;
           x = newX;
           y = newY;
           break;
         }
         else {
           sl.unlockRead(stamp);
           stamp = sl.writeLock();
         }
       }
     } finally {
       sl.unlock(stamp);
     }
   }
 }

And provided that all methods of class Point might be called from different threads:

Why exactly do we not need fields x and y to be declared as volatile?

Is it guaranteed that the code executing the Point#moveIfAtOrigin method would always see the freshest changes to the x and y fields after acquiring StampedLock#readLock?

Is there any kind of memory barrier being established when we call StampedLock#writeLock, StampedLock#readLock?

Could anyone point to a quote from documentation regarding that?

like image 954
Dmitry Gorbunov Avatar asked Aug 30 '17 09:08

Dmitry Gorbunov


1 Answers

I can't tell why that is not explicitly cited in the doc - may be because it is sort of implied, but internally that does a Unsafe.compareAndSwapLong which translates to LOCK CMPXCHG, which on x86 has full memory barrier (I assume something like this is done on other platforms); so there is no need for those to be volatile indeed.

Actually any instruction on x86 that has a lock will have a full memory barrier.

like image 126
Eugene Avatar answered Oct 19 '22 02:10

Eugene