ReentrantLock блокировать и разблокировать всегда одним и тем же потоком - PullRequest
1 голос
/ 14 марта 2019

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

Ниже приведен код, как порождаются потоки

IntStream.range(0,(NUMBER_OF_THREADS)).forEach(index ->{
            boolean operation = (index % 2 == 0) ? true : false;
            Thread t = new Thread(new Client(operation,this));
            t.start();
});

, и вот как работает функция запуска потока

@Override
public void run() {
    while(!Thread.interrupted()) {
        System.out.println("Trying to acquire lock : " + main.getLock().tryLock()
                + " thread id " + Thread.currentThread().getName());
       // if (main.getLock().tryLock()) {
        try {
            main.getLock().lock();
            if(main.getLock().isHeldByCurrentThread()) {
                System.out.println("Lock held by this thread " + main.getLock().isHeldByCurrentThread()
                        + " thread id : " + Thread.currentThread().getName());
                if (operation) {
                    main.getcAaccount().deposit(1);
                } else {
                    main.getcAaccount().withdraw(2);
                }
                Thread.currentThread().sleep(3000);
            }
        } catch (InterruptedException e) {
                e.printStackTrace();
        } finally {
            System.out.println("Thread id : " + Thread.currentThread().getName() + " unlocking");
            main.getLock().unlock();//always have the unlock part here to ensure it unlock
        }
}

Он правильно печатает, что другой5 потоков пытаются получить блокировку и перестают работать, а затем Идентификатор потока ... разблокируется ... и тот же поток снова блокируется снова, хотя он должен находиться в спящем режиме.

Я что-то пропустил в этом логическом сценарии?

Заранее спасибо.

РЕДАКТИРОВАТЬ Скриншот предлагаемого исправления.Still, same thread id unlocks and locks immediately

1 Ответ

2 голосов
/ 14 марта 2019

Повторный вход требует, чтобы за каждой блокировкой следовала последующая разблокировка. Например, если я вызову lock.lock() три раза, ожидается, что я также вызову lock.unlock() три раза. ReentrantLock не будет считать себя разблокированным, пока не произойдет эта последовательность событий.

То, что вы не понимаете, это то, что lock.tryLock(), в случае успеха, будет действовать по сути как вызов lock.lock(). Таким образом, lock дважды, вам также нужно unlock дважды. В вашем примере кода вы разблокируете только один раз, и поэтому поток, который изначально заблокирован, технически владеет блокировкой.

Исправить это должно быть просто, вы можете удалить второй lock.lock() из вашего кода, и взаимное исключение все еще должно сохраняться. Либо так, либо, если вам нужна блокировка при блокировке, замените lock.tryLock() на lock.lock().

Исходя из ваших правок, вы исправили одну проблему с удалением дополнительной блокировки, но теперь вы столкнулись с проблемой синхронизации. Вам действительно не нужно tryLock. Вы можете заменить его на lock, так как вызов lock приостановит поток и заблокирует, если блокировка уже удерживается (в конечном счете, пробуждается при вызове разблокировки).

...