Java Concurrency:具有共享访问权限的成对锁

Nei*_*ett 9 java concurrency

我正在寻找以下并发语义的Java实现.我想要ReadWriteLock除了对称之外的类似的东西,即读取和写入两个端口可以在许多线程之间共享,但是read不包括写入,反之亦然.

  1. 有两个锁,让我们称它们为A和B.
  2. 锁A是共享的,即可能有多个线程同时保存它.锁B也是共享的,可能有多个线程同时保存它.
  3. 如果任何线程持有锁A,则没有线程可能占用B - 尝试取B的线程将阻塞,直到持有A的所有线程都释放A.
  4. 如果任何线程持有锁B,则没有线程可能需要A - 尝试取A的线程将阻塞,直到所有持有B的线程都释放B.

是否有现成的库类可以实现这一目标?目前我用a近似了所需的功能,ReadWriteLock因为幸运的是在锁B的上下文中完成的任务有点罕见.虽然它感觉像是一个黑客,它可能会影响我的程序在重负载下的性能.

sta*_*off 0

怎么样

class ABSync {

    private int aHolders;
    private int bHolders;

    public synchronized void lockA() throws InterruptedException {
        while (bHolders > 0) {
            wait();
        }
        aHolders++;
    }

    public synchronized void lockB() throws InterruptedException {
        while (aHolders > 0) {
            wait();
        }
        bHolders++;
    }

    public synchronized void unlockA() {
        aHolders = Math.max(0, aHolders - 1);
        if (aHolders == 0) {
            notifyAll();
        }
    }

    public synchronized void unlockB() {
        bHolders = Math.max(0, bHolders - 1);
        if (bHolders == 0) {
            notifyAll();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:至于“公平”(或者更确切地说,不饥饿),OP 要求没有提及。为了实现OP需求+某种形式的公平/非饥饿,应该明确指定(你认为什么是公平的,当当前主导和非主导锁的请求流进来时它应该如何表现等)。实现它的方法之一是:

class ABMoreFairSync {

    private Lock lock = new ReentrantLock(true);
    public final Part A, B;

    public ABMoreFairSync() {
        A = new Part();
        B = new Part();
        A.other = B;
        B.other = A;
    }

    private class Part {
        private Condition canGo = lock.newCondition();
        private int currentGeneration, lastGeneration;
        private int holders;
        private Part other;

        public void lock() throws InterruptedException {
            lock.lockInterruptibly();
            try {
                int myGeneration = lastGeneration;
                if (other.holders > 0 || currentGeneration < myGeneration) {
                    if (other.currentGeneration == other.lastGeneration) {
                        other.lastGeneration++;
                    }
                    while (other.holders > 0 || currentGeneration < myGeneration) {
                        canGo.await();
                    }
                }
                holders++;
            } finally {
                lock.unlock();
            }
        }

        public void unlock() throws InterruptedException {
            lock.lockInterruptibly();
            try {
                holders = Math.max(0, holders - 1);
                if (holders == 0) {
                    currentGeneration++;
                    other.canGo.signalAll();
                }
            } finally {
                lock.unlock();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

 sync.A.lock();
 try {
     ...
 } finally {
     sync.A.unlock();
 }
Run Code Online (Sandbox Code Playgroud)

这里的分代思想取自《Java并发实践》,清单14.9

  • @SergeyFedorov 同步块将在测试的任一侧强制设置内存屏障。while 循环可以工作,而且实际上是[很好的实践](http://stackoverflow.com/questions/1038007/why-should-wait-always-be- Called-inside-a-loop)。 (2认同)