多个条件与多个锁

ini*_*mfs 4 java concurrency multithreading locking reentrantlock

对于特定的线程安全数据结构,我需要保护对中央数据结构(即字节数组)的访问.在这种情况下,我选择使用ReentrantLocks,因为它的公平性政策以及创建多个条件的高级功能.

并发的条件很复杂,如下所示:

  1. 中心字节数组必须独占保护(即一次一个线程).
  2. 两个访问方法(foo和bar)必须能够并发运行(如果它们尝试访问中心字节数组,则在内部阻塞).
  3. 对任何方法(foo和bar)的调用都需要是独占的(即从不同的线程多次调用foo将导致一个线程阻塞).

在我最初的实现中,我选择实现两个嵌套锁,如下所示:

ReentrantLock lockFoo = new ReentrantLock(true);
ReentrantLock lockCentral = new ReentrantLock(true);

Condition centralCondition = lockCentral.newCondition();

public void foo(){
    // thread-safe processing code here

    lockFoo.lock();        
    lockCentral.lock();

    try{
        // accessing code here

        try{
            // waits upon some condition for access
            while(someCondition){
                centralCondition.await();
            }
        }catch(InterruptedException ex){
            // handling code here
        }

        // more processing
    }finally{
        lockCentral.unlock();
        lockFoo.unlock();
    }
}
Run Code Online (Sandbox Code Playgroud)

结构在方法上是等效的bar,只需用另一个锁对象lockBar.此外,代码减少了我更复杂的多条件等待,并为简单起见信号到单一条件.

使用这个,我不禁感到代码看起来不必要地复杂和模糊不仅因为有两个嵌套的锁,它们共享一个try-finally,更不用说如何在整个过程中lockCentral释放和重新获取多次lockFoo.

相反,我试图重新组织外锁(lockFoolockBar)作为一个条件lockCentral,如下所示:

ReentrantLock lockCentral = new ReentrantLock(true);

Condition fooCondition = lockCentral.newCondition();
Condition centralCondition = lockCentral.newCondition();

boolean isInFoo = false;

public void foo(){
    // thread-safe processing code here

    lockCentral.lock();

    try{
        // implement method exclusiveness via fooCondition

        try{
            while(isInFoo){
                fooCondition.await();
            }

            isInFoo = true;
        }catch(InterruptedException ex){
            return;
        }

        // accessing code here

        try{
            // waits upon some condition for access
            while(someCondition){
                centralCondition.await();
            }
        }catch(InterruptedException ex){
            // handling code here
        }

        // more processing
    }finally{
        isInFoo = false;
        fooCondition.signal();

        lockCentral.unlock();
    }
}
Run Code Online (Sandbox Code Playgroud)

在一些检查之后,我无法决定前者是更好的想法还是后者(特别是包含那个随机布尔值).简化代码的想法似乎导致了更长的代码,在这种情况下非常违反直觉.

有没有一些惯例或令人信服的理由来论证:

  1. 每个锁定上下文使用一个锁(前一个代码,其中锁定的不同原因共享不同的锁).

  2. 每个锁定资源使用一个锁(后一个代码,其中要保护的中央结构使用单个锁,其他所有其他实现为访问所述结构的条件).

Tsy*_*rev 5

后者代码不同于前者只是通过手动实现锁的lockFoofooCondition(同样是真正的酒吧 -相关的部分).

因为这样的锁实现被考虑在内,那个foo临界区几乎与中心区相同,所以如果没有争用foo()(在这种情况下从不执行等待fooCondition),则保证更快.

除了性能原因之外,以前的代码是可取的,因为它是自我记录的.此外,它可以扩展到需要在没有lockCentral的情况下访问受lockFoo保护的数据的情况.在这种情况下,锁的手动实现会失去其性能.