不同线程释放的ReentrantReadWriteLock

ReentrantReadWriteLock released by different thread

我正在单个服务器上实施乐观交易 (BOCC)。在提交时,根据当前数据库状态验证读取和写入集(如果读取后状态发生变化,事务将中止)。如果验证成功,所有对象都将写入数据库。

不同对象集的验证(加上数据库更新)可以并发,但重叠的对象集必须使用读写锁来保护。

我使用 ReentrantReadWriteLock 来保护验证,效果很好。现在我正在编写一个恢复机制,如果由于某些错误(验证后)不是所有对象都写入数据库,它会重复更新过程。

因此恢复会重复数据库写入,然后尝试释放锁(在恢复成功后)。问题是我试图从另一个线程释放锁(因为恢复是由另一个后台服务执行的),这会引发 IllegalMonitorStateExceptionunlock 方法上的注释验证了此行为。

    /**
     * Attempts to release this lock.
     *
     * <p>If the current thread is the holder of this lock then
     * the hold count is decremented. If the hold count is now
     * zero then the lock is released.  If the current thread is
     * not the holder of this lock then {@link
     * IllegalMonitorStateException} is thrown.
     *
     * @throws IllegalMonitorStateException if the current thread does not
     * hold this lock
     */
    public void unlock() {

现在我的问题是:Java 中是否有我可以在需要时使用的锁:

一般来说,将锁从不同的线程释放到请求锁的线程是个坏主意。这样做会引发各种竞争条件和其他意外行为。例如,如果最初申请锁的线程因为不知道其他线程已经处理它并释放了锁而开始更改事物,会发生什么情况?

改为向原始线程发送一个信号,说明它已被处理并释放锁。

tryLock 确实可以让您无需等待即可尝试获取锁。

ReentrantReadWriteLock http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html 似乎可以满足您的需要,只要您发出释放锁的信号即可。

您要么需要在原始线程上进行重试,要么让原始线程等待(持有锁)直到重试完成,然后自行释放它们。只有申请锁的线程才能释放锁,这几乎是线程的通用规则,因此不会有太多替代选项。

当然,除非您想实现自己的锁(例如,最基本级别的 AtomicBoolean 可以被认为是写锁,以及 AtomicInteger 用于读锁)。那是你可能打开的一大罐蠕虫。正确获得线程和同步是困难

正如@TimB 指出的那样,一个线程释放(即破坏)另一个线程的锁是一件危险的事情通常

但是,如果您想在允许的地方实施自定义锁,您应该能够做到。如果您查看 java.util.concurrent.locks.ReentrantReadWriteLock 的实现,例如 (here),Sync.tryReleaseShared(int) 实现释放锁的逻辑。如果您检查它,它实际上正在执行您正在谈论的检查,并在代码中明确抛出异常。虽然我不认为这会是一件简单的事情,但应该可以 将该行为更改为适合您的框架的行为。

我知道任何现有的 "breakable" 锁实现吗?不,我在 GrepCode 中找不到。

为什么?可能是因为其他人对破锁的效用(和安全性)持怀疑态度。

StampedLock 对我有用,可以从另一个线程解锁。我将其用作:

ReadWriteLock lock = new StampedLock().asReadWriteLock();