用于暂停操作的信号量,不限制并发操作

Semaphore for pausing actions, not limiting concurrent actions

我有一个方法,该方法经常被许多在数据结构中查找数据的线程调用。

当需要更新该数据结构时,我需要阻止所有尝试查找的线程,直到更新完成。

我可以使用具有 X 许可的信号量,并让更新方法在执行更新之前获取所有 X 许可,然后再次释放它们 - 但现在 X 还用于将我的查找方法限制为 X 个同时调用的次要目的,我不想要。

我还有哪些其他选项可以在不限制同时执行的情况下阻止对更新方法的调用?

考虑使用 ReadWriteLock,特别是 ReentrantReadWriteLock。每个读取线程都可以锁定 readLock,当需要写入时,只需锁定 writeLock

写锁被持有时,将阻止所有读取(和后续写入)发生,直到写锁被释放。持有 readLock 的线程可以同时执行。即多个线程可以同时持有readLock。

如果您使用 Java 8 我建议 StampedLock

John Vint 的回答——reader/writer 锁——听起来最适合你的问题,但你让我想到了一种古老且非常简单的设计模式,称为 "turnstile"。

(警告!这是一个非答案:十字转门实际上并没有解决问题。它可以阻止线程进入查找例程,但它对当更新程序线程变为活动状态时,已经 查找例程中的线程。)

无论如何,十字转门可以追溯到信号量被认为是低级原语的时代,所有其他同步对象都可以从中派生。 (比 Java 早得多)。可能有更有效的方法来做到这一点,但我一直喜欢实现的简单性:

class Turnstile {
    private final Semaphore semaphore = new Semaphore(1);

    // To be called in threads that need to "pass through" the turnstile.
    public void passThrough() {
        semaphore.acquire();
        semaphore.release();
    }

    // To be called only in the single thread that owns the turnstile.
    public void lock() {
        semaphore.acquire();
    }

    // To be called only in the single thread that owns the turnstile.
    public void unlock() {
        semaphore.release();
    }
}