Multiple conditions against multiple locks

For a specific thread-safe data structure, I need to protect access to the central data structure (namely, an array of bytes). I prefer to use ReentrantLocks in this case for an honesty policy, as well as for advanced features when creating multiple conditions.

The conditions for concurrency are complex and are listed below:

  • The central byte array must be protected exclusively (i.e. one stream at a time).
  • Two access methods (foo and bar) should work simultaneously (blocking internally if they try to access the array of central bytes).
  • A call to any method (foo and bar) must be exceptional (i.e. multiple calls to foo from different threads will block the thread).

In my initial implementation, I decided to implement two nested locks, as shown below:

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();
    }
}

the structure is equivalent in a method bar, just with another lock object lockBar. In addition, the code simplified my more complex layered wait and signals to one condition for simplicity.

Using this, I cannot help but feel that the code seems overly complex and unclear in the fact that not only the nested two locks are nested, they share one attempt - finally, not to mention how it lockCentralcan be released and re-acquired several times, while it lockFooremains everywhere.

Instead, I tried to reconstruct the outer lock ( lockFooand lockBar) instead of the condition lockCentral, as shown below:

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();
    }
}

, ( ). , -, , .

- :

  • ( , ).

  • ( , , , , ).

+4
2

Latter lockFoo fooCondition ( ).

, foo , , , , foo() ( fooCondition ).

, , . , , , lockFoo, . .

+5

lockFoo lockBar , foo(), bar() lockCentral. , lockCentral - , .


, , " ", . , lockFoo lockBar . ? , .


? : " (foo bar) ". : ; .

" ?" ? ?

, foo()? ? , bar()? ?

, foo() () ?

, :

SomeObject someObject;
SomeOtherObject someOtherObject;
boolean success = false;
while (! success) {

    someLock.lock();
    try {
        someObject = getLocalCopyOfSomeData();
        someOtherObject = getLocalCopyOfSomeOtherData();
    } finally {
        someLock.unlock();
    }

    doTheRealWork(someObject, someOtherObject);

    someLock.lock();
    try {
        success = updateCentralCopyOf(someObject) || updateCentralCopyOf(someOtherObject);
    } finally {
        someLock.unlock();
    }
}
0

Source: https://habr.com/ru/post/1585087/


All Articles