【问题标题】:Why does a lock force you to wait until you actually have a lock?为什么锁会迫使您等到您真正拥有锁?
【发布时间】:2013-04-22 21:21:15
【问题描述】:

在Java 的实现锁中,没有办法将锁从读锁自动升级为写锁。比如下面的代码sn -p 失败

ReentrantReadWriteLock lock = new ...

lock.readLock().lock();

boolean mustWrite = false;
// do somestuff and determine you must instead write! :-O
if(mustWrite) {
    lock.writeLock().lock();
    writeSomeStuff();
    lock.writeLock().unlock();
}
lock.readLock.unlock();

写锁获取必须等待所有读锁都完成,这样它才知道它不会覆盖读者可能正在读取的数据。那很糟。所以解决方法是做这样的事情:

if(mustWrite) {
    lock.readLock().unlock(); // let go of read before writing
    lock.writeLock().lock();
    writeSomeStuff();
    lock.writeLock().unlock();
    lock.readLock().lock(); // get back to reading
}

但这并不理想 - 当您解锁读取并开始写入时,有人可能会去做一些事情。现在,无论如何仔细检查这些条件可能是个好主意,但仍然 - 它很丑。

现在,通常情况下,当您获取锁时,您希望强制代码等待它实际获取,然后再执行您正在执行的操作。您不想只相信您的锁定机制,它会在您开始弄乱数据之前为您提供锁定。

但是为什么它会强制你从你发出想要锁的信号到你真正被读取等待时停止执行呢?例如,为什么它不能允许这样的事情:

lock.writeLock().notifyIntentToLock(); // puts you in line to get the write lock
                                       // everyone else will block until you both
                                       // acquire and release the lock
lock.readLock().unlock(); // proceed with the unlock so you don't deadlock
lock.writeLock().makeGoodOnIntentToLock(); // actually acquire that lock

所以从某种意义上说,当前的锁功能可以被理论化为它们都是同时完成的,比如

public void lock() {
    this.notifyIntentToLock();
    this.makeGoodOnIntentToLock();
}

哪些设计决策会使它们不允许某种延迟意图锁定?这样的锁设计是否存在我根本看不到的严重问题?

【问题讨论】:

  • 一种锁,让您无需等待即可保留它,并允许您稍后再查看,希望此时您已经获得它并且您不必再等待。我实际上认为这是一个非常好的主意。它可能具有比其他类型的锁更复杂的实现——我不确定。人们可能能够在较低级别的原语之上有效地实现它,就像在互斥锁和/或硬件比较和交换指令等更简单的原语之上实现读写器锁一样。
  • 这里是新手,但这样的功能不会鼓励应用程序非常贪婪吗?例如,如果我知道稍后在我的程序中需要一个文件,我可能会在一开始就notifyIntentToLock,拒绝任何其他应用程序访问它[可能]比实际需要的时间长得多。
  • @Supericy 好吧,他们当然可以。但他们已经可以做到这一点——他们可以一开始就打电话给lock。因此,它不会引入任何新的诱惑来滥用已经不存在的 API。
  • @Celada,硬件比较和交换指令 - 一切都在它们之上实现 r LL/SC(加载链接/存储条件)替代方案。编写一个简单的 RW 锁实际上非常困难。 Java8 有 StampedLock,它的使用可能需要一个循环,但最重要的是它需要在 java 中添加 a load/load barrier 以使其正常工作。

标签: java locking reentrantreadwritelock


【解决方案1】:

在决定使用排他锁后,你要做的就是:

  • 离开读锁,
  • 获取写锁和
  • 再次检查条件
  • 根据结果,继续或退出。

关于获取写锁的意图,当多个并发意图存在时会发生什么?可能所有人都必须检查初始条件,因为无法确定谁会成为受害者(在获胜者之后授予锁定)。

还有更多 - impl。 RW 锁的启动很糟糕,因为读取会修改导致一致性流量的元数据 - 因此 RW 锁不能很好地扩展。

【讨论】:

  • 请,立即使用 writeLock 十次执行(一致)读取和写入的处理有什么区别,或者上面的解决方案,您使用 readLock 执行附加读取并将结果与​​ writeLock 中的附加读取进行比较堵塞? A 认为唯一不同的是识别数据已更改,但与单个 writeLock 块相反的优势在哪里数据始终一致?
猜你喜欢
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多