简体   繁体   English

Java 中的 StampedLock 是什么?

[英]What is StampedLock in Java?

I am working on a Java code, I need to implement threading in it.我正在处理 Java 代码,我需要在其中实现线程。 I was going through JAVA 8 API and I come to know about Stamped Locks.我正在研究 JAVA 8 API,我开始了解 Stamped Locks。 Can anyone tell me why to use StampedLocks in multithreading?谁能告诉我为什么要在多线程中使用 StampedLocks?

StampedLock is an alternative to using a ReadWriteLock (implemented by ReentrantReadWriteLock). StampedLock 是使用 ReadWriteLock(由 ReentrantReadWriteLock 实现)的替代方法。 The main differences between StampedLock and ReentrantReadWriteLock are that: StampedLock 和 ReentrantReadWriteLock 的主要区别在于:

  • StampedLocks allow optimistic locking for read operations StampedLocks 允许对读操作进行乐观锁定
  • ReentrantLocks are reentrant (StampedLocks are not) ReentrantLocks 是可重入的(StampedLocks 不是)

So if you have a scenario where you have contention (otherwise you may as well use synchronized or a simple Lock ) and more readers than writers, using a StampedLock can significantly improve performance.因此,如果您遇到争用情况(否则您也可以使用synchronized或简单的Lock )并且读取器多于写入器,则使用 StampedLock 可以显着提高性能。

However you should measure the performance based on your specific use case before jumping to conclusions.但是,在得出结论之前,您应该根据您的特定用例来衡量性能。

Heinz Kabutz has written about StampedLocks in his newsletter and he also made a presentation about performance . Heinz Kabutz在他的时事通讯中写了关于 StampedLocks 的文章,他还做了一个关于性能的演讲

The API documentation for java.util.concurrent.locks.StampedLock says: java.util.concurrent.locks.StampedLock的 API 文档说:

StampedLocks are designed for use as internal utilities in the development of thread-safe components. StampedLocks 旨在用作开发线程安全组件的内部实用程序。 Their use relies on knowledge of the internal properties of the data, objects, and methods they are protecting.它们的使用依赖于对它们所保护的数据、对象和方法的内部属性的了解。 They are not reentrant, so locked bodies should not call other unknown methods that may try to re-acquire locks (although you may pass a stamp to other methods that can use or convert it).它们不是可重入的,因此锁定的主体不应调用其他可能尝试重新获取锁的未知方法(尽管您可以将标记传递给其他可以使用或转换它的方法)。 The use of read lock modes relies on the associated code sections being side-effect-free.读取锁定模式的使用依赖于无副作用的相关代码段。 Unvalidated optimistic read sections cannot call methods that are not known to tolerate potential inconsistencies.未经验证的乐观读取部分不能调用已知的方法来容忍潜在的不一致。 Stamps use finite representations, and are not cryptographically secure (ie, a valid stamp may be guessable).邮票使用有限的表示,并且在密码学上不是安全的(即,有效的邮票可能是可猜到的)。 Stamp values may recycle after (no sooner than) one year of continuous operation.邮票值可以在(不早于)连续运行一年后回收。 A stamp held without use or validation for longer than this period may fail to validate correctly.超过此期限而未使用或验证的邮票可能无法正确验证。 StampedLocks are serializable, but always deserialize into initial unlocked state, so they are not useful for remote locking. StampedLocks 是可序列化的,但总是反序列化为初始解锁状态,因此它们对远程锁定没有用。

eg -例如——

 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);
     }
   }
 }

StampedLock support read and write locks. StampedLock 支持读写锁。 In contrast to ReadWriteLock the locking methods of a StampedLock return a stamp represented by a long value.与 ReadWriteLock 相比,StampedLock 的锁定方法返回一个由 long 值表示的戳记。 You can use these stamps to either release a lock or to check if the lock is still valid.您可以使用这些标记来释放锁定或检查锁定是否仍然有效。 Additionally stamped locks support another lock mode called optimistic locking.此外,标记锁支持另一种称为乐观锁的锁模式。

ExecutorService executor = Executors.newFixedThreadPool(2);
        Map<String, String> map = new HashMap<>();
        StampedLock lock = new StampedLock();

        executor.submit(() -> {
            long stamp = lock.writeLock();
            try {
                Thread.sleep(100);
                map.put("test", "INDIA");
            } catch (Exception e) {
            } finally {
                lock.unlockWrite(stamp);
            }
        });

        Runnable readTask = () -> {
            long stamp = lock.readLock();
            try {
                System.out.println(map.get("test"));
                Thread.sleep(100);
            } catch (Exception e) {
            } finally {
                lock.unlockRead(stamp);
            }
        };

        executor.submit(readTask);
        executor.submit(readTask);

Obtaining a read or write lock via readLock() or writeLock() returns a stamp which is later used for unlocking within the finally block.通过 readLock() 或 writeLock() 获得读或写锁会返回一个标记,该标记稍后用于在 finally 块中解锁。 Keep in mind that stamped locks don't implement reentrant characteristics.请记住,标记锁不实现可重入特性。 Each call to lock returns a new stamp and blocks if no lock is available even if the same thread already holds a lock.每次调用 lock 都会返回一个新的标记,如果没有可用的锁,即使同一个线程已经持有锁,也会阻塞。 So you have to pay particular attention not to run into deadlocks.所以你要特别注意不要陷入僵局。

executor.submit(() -> {
            long stamp = lock.tryOptimisticRead();
            try {
                System.out.println("Optimistic Lock Valid: " + lock.validate(stamp));
                Thread.sleep(100);
                System.out.println("Optimistic Lock Valid: " + lock.validate(stamp));
                Thread.sleep(1000);
                System.out.println("Optimistic Lock Valid: " + lock.validate(stamp));
            } catch (Exception e) {
            } finally {
                lock.unlock(stamp);
            }
        });

        executor.submit(() -> {
            long stamp = lock.writeLock();
            try {
                System.out.println("Write Lock acquired");
                Thread.sleep(100);
            } catch (Exception e) {
            } finally {
                lock.unlock(stamp);
                System.out.println("Write done");
            }
        });

An optimistic read lock is acquired by calling tryOptimisticRead() which always returns a stamp without blocking the current thread, no matter if the lock is actually available.乐观读锁是通过调用 tryOptimisticRead() 获取的,无论锁是否实际可用,它始终返回一个标记而不阻塞当前线程。 If there's already a write lock active the returned stamp equals zero.如果已经有一个写锁处于活动状态,则返回的戳记为零。 You can always check if a stamp is valid by calling lock.validate(stamp).您始终可以通过调用 lock.validate(stamp) 来检查图章是否有效。

In addition to @assylias answer :除了@assylias 的回答

StampedLock supports upgrading readLock to writeLock using method tryConvertToWriteLock(long) : StampedLock 支持使用tryConvertToWriteLock(long)方法将 readLock 升级为 writeLock:

java doc : 爪哇文档

This class also supports methods that conditionally provide conversions across the three modes.此类还支持有条件地提供跨三种模式的转换的方法。 For example, method tryConvertToWriteLock(long) attempts to "upgrade" a mode, returning a valid write stamp if (1) already in writing mode (2) in reading mode and there are no other readers or (3) in optimistic mode and the lock is available.例如,方法 tryConvertToWriteLock(long) 尝试“升级”模式,如果 (1) 已经处于写入模式 (2) 处于读取模式并且没有其他读取器或 (3) 处于乐观模式并且锁可用。 The forms of these methods are designed to help reduce some of the code bloat that otherwise occurs in retry-based designs.这些方法的形式旨在帮助减少一些在基于重试的设计中出现的代码膨胀。

code samples:代码示例:

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

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

   // a read-only method
   // upgrade from optimistic read to read lock
   double distanceFromOrigin() {
     long stamp = sl.tryOptimisticRead();
     try {
       retryHoldingLock: for (;; stamp = sl.readLock()) {
         if (stamp == 0L)
           continue retryHoldingLock;
         // possibly racy reads
         double currentX = x;
         double currentY = y;
         if (!sl.validate(stamp))
           continue retryHoldingLock;
         return Math.hypot(currentX, currentY);
       }
     } finally {
       if (StampedLock.isReadLockStamp(stamp))
         sl.unlockRead(stamp);
     }
   }

   // upgrade from optimistic read to write lock
   void moveIfAtOrigin(double newX, double newY) {
     long stamp = sl.tryOptimisticRead();
     try {
       retryHoldingLock: for (;; stamp = sl.writeLock()) {
         if (stamp == 0L)
           continue retryHoldingLock;
         // possibly racy reads
         double currentX = x;
         double currentY = y;
         if (!sl.validate(stamp))
           continue retryHoldingLock;
         if (currentX != 0.0 || currentY != 0.0)
           break;
         stamp = sl.tryConvertToWriteLock(stamp);
         if (stamp == 0L)
           continue retryHoldingLock;
         // exclusive access
         x = newX;
         y = newY;
         return;
       }
     } finally {
       if (StampedLock.isWriteLockStamp(stamp))
         sl.unlockWrite(stamp);
     }
   }

   // Upgrade read lock to write lock
   void moveIfAtOrigin(double newX, double newY) {
     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);
     }
   }
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM