首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不稳定的StampedLock.unlock(长)行为?

不稳定的StampedLock.unlock(长)行为?
EN

Stack Overflow用户
提问于 2015-06-04 15:05:14
回答 2查看 472关注 0票数 7

关于StampedLock,我面临着一种奇怪的行为。下面是主要有问题的代码行:

代码语言:javascript
复制
StampedLock lock = new StampedLock();
long stamp1 = lock.readLock();
System.out.printf("Read lock count: %d%n", lock.getReadLockCount());
lock.unlock(stamp1 + 2);
System.out.printf("Read lock count: %d%n", lock.getReadLockCount());

奇怪的行为是如何解锁“容忍”错误的阅读印章。你觉得这是对的吗?

以下是完整的代码以供参考:

代码语言:javascript
复制
public class StampedLockExample {
  static StampedLock lock = new StampedLock();

  static void println(String message, Object... args) {
    System.out.printf(message, args);
    System.out.println();
  }

  static void printReadLockCount() {
    println("Lock count=%d", lock.getReadLockCount());
  }

  static long tryReadLock() {
    long stamp = lock.tryReadLock();
    println("Gets read lock (%d)", stamp);
    printReadLockCount();
    return stamp;
  }

  static long tryWriteLock() {
    long stamp = lock.tryWriteLock();
    println("Gets write lock (%d)", stamp);
    return stamp;
  }

  static long tryConvertToReadLock(long stamp) {
    long newOne = lock.tryConvertToReadLock(stamp);
    println("Gets read lock (%d -> %d)", stamp, newOne);
    printReadLockCount();
    return newOne;
  }

  static void tryUnlock(long stamp) {
    try {
      lock.unlock(stamp);
      println("Unlock (%d) successfully", stamp);
    } catch (IllegalMonitorStateException e) {
      println("Unlock (%d) failed", stamp);
    }
    printReadLockCount();
  }

  public static void main(String[] args) {
    println("%n--- Gets two read locks ---");
    long stamp1 = tryReadLock();
    long stamp2 = tryReadLock();
    long min = Math.min(stamp1, stamp2);
    long max = Math.max(stamp1, stamp2);

    println("%n--- Tries unlock (-1 / +2 / +4) ---");
    tryUnlock(min - 1);
    tryUnlock(max + 2);
    tryUnlock(max + 4);

    println("%n--- Gets write lock ---");
    long stamp3 = tryWriteLock();

    println("%n--- Tries unlock (-1 / +1) ---");
    tryUnlock(stamp3 - 1);
    tryUnlock(stamp3 + 1);

    println("%n--- Tries write > read conversion ---");
    long stamp4 = tryConvertToReadLock(stamp3);

    println("%n--- Tries unlock last write stamp (-1 / 0 / +1) ---");
    tryUnlock(stamp3 - 1);
    tryUnlock(stamp3);
    tryUnlock(stamp3 + 1);

    println("%n--- Tries unlock (-1 / +1) ---");
    tryUnlock(stamp4 - 1);
    tryUnlock(stamp4 + 1);
  }
}

输出:

代码语言:javascript
复制
--- Gets two read locks ---
Gets read lock (257)
Lock count=1
Gets read lock (258)
Lock count=2

--- Tries unlock (-1 / +2 / +4) ---
Unlock (256) failed
Lock count=2
Unlock (260) successfully
Lock count=1
Unlock (262) successfully
Lock count=0

--- Gets write lock ---
Gets write lock (384)

--- Tries unlock (-1 / +1) ---
Unlock (383) failed
Lock count=0
Unlock (385) failed
Lock count=0

--- Tries write > read conversion ---
Gets read lock (384 -> 513)
Lock count=1

--- Tries unlock last write stamp (-1 / 0 / +1) ---
Unlock (383) failed
Lock count=1
Unlock (384) failed
Lock count=1
Unlock (385) failed
Lock count=1

--- Tries unlock (-1 / +1) ---
Unlock (512) failed
Lock count=1
Unlock (514) successfully
Lock count=0
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-07-08 08:17:21

简短回答:

在邮票中添加两个是在修改它的一部分,这不需要在读模式锁中进行验证。

长答案:

该邮票包含两部分信息:一个状态序列号,以及有多少读取器。状态号存储在邮票的前57位中,读取器计数存储在最后7位中。因此,当您将2添加到邮票中时,您将读取器计数从1更改为3,并保持状态号不变。由于StampedLock是在读取模式下才获得的,因此只验证了状态号,忽略了读取器计数。这是有意义的,因为读锁应该能够以任何顺序解锁。

例如:从现有的StampedLock中获取读邮票,其状态号为4,读取器计数为1。从同一StampedLock获取第二读邮票,状态数为4,读取器计数为2。请注意,邮票的状态号是相同的,因为邮票锁的状态在获得邮票之间没有变化。第一读邮票用于解锁。第一个邮票(4)的状态号与StampedLock (4)的状态号相匹配,所以这很好。第一个邮票(1)的读取器计数与StampedLock (2)的读取器计数不匹配,但这并不重要,因为读锁应该能够按任何顺序解锁。解锁成功了。

请注意,StampedLocks设计为高性能的读/写锁。用于内部实用程序,而不是承受恶意编码的东西,因此它是在其预期的边界内操作的。不过,我确实认为解锁()的Javadoc是误导性的。

票数 6
EN

Stack Overflow用户

发布于 2015-07-08 12:46:45

javadocs的关键部分是:

邮票使用有限的表示,并且不是密码安全的(例如,有效的邮票可以猜测)。

这意味着您应该将它们视为不透明的值,而不是试图以任何方式修改它们。

本质上可以猜测的是你的-1,+2,+4算法所做的事情。如果您有一个很好的猜测起点,比如之前的令牌,那么这不仅是可以猜测的,而且很容易做到。

此外,StampedLock.validate(long)声明:

用未从tryOptimisticRead()获得的值或此锁的锁定方法调用此方法没有定义的效果或结果。

换句话说:任何不是直接从Lock方法中获得的令牌值不仅无效,而且还包含未定义的行为。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30647525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档