Дождитесь разблокировки замка, не блокируя его после разблокировки - PullRequest
0 голосов
/ 10 января 2019

Извините, если название - скороговорка, но я не смог бы сформулировать это лучше, потому что это именно то, что я хочу сделать.

У меня есть этот метод / код:

// No need fairness (false) the first to get it is good to go
private final Lock TEST = new ReentrantLock(false)

public methodCalledByMultipleThreads() {

    // 1st code section - no concurrency problems
    // regardless of what happen in section 2 a thread that just called
    // this function should always be able to run section 1

    // 2nd code section begin

    if (rare_condition && TEST.tryLocking()) {
        // check again to avoid limit cases where "rare_condition" value
        // is invalidated by another thread (who ran "important stuffs")
        // and just released/unlock TEST with "TEST.unlock();"
        if (check_rare_condition_again) {
            // ##### do "important stuffs" ##### 
            // release lock
            TEST.unlock();
        }
    }

    TEST.waitUntilUnlocked(); // this is what I actually would like to do
    // ##### do other stuffs ##### 

}

Конечно, «waitUntilUnlocked» не должен блокировать «TEST», когда ожидание закончено. Я пытался получить желаемое поведение с помощью хакерского использования семафора ... что очень плохо, семафоры не созданы для этого и в этом случае также приводят к накладным расходам (внутренний счет разрешений ничего не учитывает ... просто необычный замок):

private final Lock TEST = new ReentrantLock(false)

// absurd high value (Integer.MAX_VALUE) for permits, to allow "virtually"
// infinite threads to works with this code
private final Semaphore SEM = new Semaphore(Integer.MAX_VALUE, true);

public methodCalledByMultipleThreads() {

    // 1st code section

    // 2nd code section begin

    if (rare_condition && TEST.tryLocking()) {
        if (check_rare_condition_again) {

            // waits to gets all permits
            SEM.acquireUninterruptibly(Integer.MAX_VALUE);

            // ##### do important stuffs ##### 

            // release all permits
            SEM.release(Integer.MAX_VALUE);
            // release lock
            TEST.unlock();
        }
    }
    // ask one permit
    SEM.acquireUninterruptibly();
    //  ##### do other stuffs ##### 
    // release one permit
    SEM.release();

}

Вышеупомянутое решение "работает" (к счастью, в реальной реализации код достаточно медленный, чтобы не вызывать крайние случаи ... на данный момент), но теоретически неверен, так как "SEM.release (Integer.MAX_VALUE);" и "TEST.unlock ();" должно быть одно.

Как я могу получить такое поведение без этого уродливого взлома?

...