Как заставить потоки ждать выхода ReentrantLock? - PullRequest
1 голос
/ 16 мая 2019

Если поток получил блокировку, я хочу, чтобы другие потоки пропустили попытку установить блокировку и просто подождать, пока блокировка будет снята, прежде чем продолжить выполнение. Я НЕ хочу, чтобы другие потоки получали блокировку после ее снятия.

Я читал эту тему, но все еще в замешательстве.

См. Следующий обобщенный фрагмент кода ниже:

private final ReentrantLock reentrantLock = new ReentrantLock();

public void aCoolMethod(){
    if (reentrantLock.tryLock() == true){
        try {
            doSomething();
        } finally {
            reentrantLock.unlock();
        }
    } else {
        // have threads wait until reentrantLock is unlocked
    }
    doSomethingElse();
}

Как мне сделать так, чтобы потоки, входящие в мой блок else, ожидали разблокировки повторной входящей блокировки перед продолжением выполнения?

Ответы [ 2 ]

2 голосов
/ 16 мая 2019

Как упоминал Тило, лучшим способом решения вашей проблемы является наличие критической секции, содержащей флаг, который сначала проверяют потоки.Если флаг не был установлен, исправьте свою проблему и установите флаг перед выходом из критической секции.Если флаг был установлен, вы знаете, что другой поток первым пришел туда и устранил проблему, поэтому просто выйдите из критической секции.

private final ReentrantLock reentrantLock = new ReentrantLock();
private boolean fixed = false;

public void aCoolMethod(){
    try {
        reentrantLock.lock();

        if (!fixed) {
            doSomething();
        }
    } finally {
        fixed = true;
        reentrantLock.unlock();
    }

    doSomethingElse();
}

В качестве альтернативы, без блокировок вы можете использовать объект консенсуса, чтобы определить, какой потокработает doSomething():

private final AtomicBoolean turn = new AtomicBoolean(true);
private volatile boolean done = false;

public void aCoolMethod(){
    if (turn.compareAndSet(true, false)) {
        doSomething();
        done = true;
    } else {
        while (!done) {
          // spin or wait for condition
        }
        doSomethingElse();
    }
}
0 голосов
/ 04 июня 2019

Публикация решения, которое я использовал в случае, если у кого-то еще есть подобная проблема. Я решил использовать стратегию ожидания-уведомления. В то время как другие ответы были полезны, это хорошо работает для моей ситуации и достаточно просто.

private final ReentrantLock reentrantLock = new ReentrantLock();

public void aCoolMethod(){
    if (reentrantLock.tryLock()){
        try {
            doSomething();
        } finally {
            reentrantLock.unlock();
            synchronized (reentrantLock) {
                reentrantLock.notifyAll();
            }
        }
    } else {
        // have threads wait until reentrantLock is unlocked
        synchronized (reentrantLock) {
            while(reentrantLock.isLocked()) {
                try {
                    reentrantLock.wait();
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    doSomethingElse();
}

Редактировать: Опубликовать тестовый класс, чтобы другие могли проверить это решение. Просто скопируйте / вставьте и запустите его. Смотрите ниже:

import java.util.concurrent.locks.ReentrantLock;
import java.lang.Thread;

public class LockTest {

    public static void main(String args[]){
        TestClass testClass = new TestClass();

        Thread thread0 = new Thread () {
            public void run () {
                testClass.testLock();
            }
        };
        Thread thread1 = new Thread () {
            public void run () {
                testClass.testLock();
            }
        };
        Thread thread2 = new Thread () {
            public void run () {
                testClass.testLock();
            }
        };

        thread0.start();
        thread1.start();
        thread2.start();

    }

    public static class TestClass{
        ReentrantLock reentrantLock = new ReentrantLock();

        public void testLock(){
            if (reentrantLock.tryLock()) {
                try {
                    System.out.println("Locking");
                    System.out.println(Thread.currentThread().getName() + " will sleep");
                    Thread.sleep(8000);
                    System.out.println(Thread.currentThread().getName() + " has woken up from sleep!!");
                } catch (InterruptedException i) {
                    System.out.println("Interrupted during sleep");
                } finally {
                    System.out.println("Unlocking");
                    reentrantLock.unlock();
                    System.out.println("Notifying");
                    synchronized (reentrantLock) {
                        reentrantLock.notifyAll();
                    }
                }
            } else {
                synchronized (reentrantLock) {
                    while(reentrantLock.isLocked()) {
                        try {
                            System.out.println(Thread.currentThread().getName() + " will wait");
                            reentrantLock.wait();
                            System.out.println(Thread.currentThread().getName() + " has woken up from wait!!");
                        } catch (InterruptedException i) {
                            System.out.println("Interrupted during wait");
                        }
                    }
                }
            }
            System.out.println(Thread.currentThread().getName() + " has reached the end.");
        }

    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...