为什么我们不需要与StampedLock挥发?

时间:2017-08-30 09:05:55

标签: java multithreading java-8 volatile memory-barriers

给出来自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);
     }
   }
 }

并且可以从不同的线程调用Point类的所有方法:

为什么我们不需要将字段x和y声明为volatile?

是否可以保证执行Point#moveIfAtOrigin方法的代码在获取StampedLock#readLock后始终会看到对x和y字段的最新变化?

当我们致电StampedLock#writeLockStampedLock#readLock时,是否存在任何类型的记忆障碍?

有人能指出有关该文件的文献引用吗?

2 个答案:

答案 0 :(得分:2)

我不知道为什么在文档中没有明确引用 - 可能是因为它有点隐含,但在内部执行Unsafe.compareAndSwapLong转换为LOCK CMPXCHGx86full memory barrier 1}}有volatile(我假设这样的事情在其他平台上完成);所以没有必要确实x86

实际上,lock上有RuntimeWarning: divide by zero encountered in divide 的任何指令都会有完整的内存屏障。

答案 1 :(得分:2)

Lock接口的Javadoc声明如下:

  

内存同步

     

所有Lock实现必须强制执行内置监视器锁提供的相同内存同步语义,如Java语言规范(17.4内存模型)中所述:

     

成功的锁定操作与成功的锁定操作具有相同的内存同步效果。   成功解锁操作具有与成功解锁操作相同的内存同步效果。   不成功的锁定和解锁操作以及重入锁定/解锁操作不需要任何内存同步效果。

即使StampedLock没有实现Lock,它也有asReadLock()之类的方法:

  

返回此StampedLock的普通Lock视图,其中Lock.lock()方法映射到readLock(),其他方法也是如此。

它返回StampedLock内部类ReadLockView的实例,它是Lock的实际实现。

但是因为它只是一个委托者,这意味着原始方法必须创建内存障碍才能符合Lock接口的内存同步实施。