Пример синхронизации Bow / Bower в руководстве по Java-оракулу с блокировкой повторного входа - PullRequest
0 голосов
/ 27 апреля 2018

Код, приведенный здесь на https://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html, обеспечивает синхронизацию лука и беседки с объектами блокировки, чтобы избежать тупика.

вот код

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;

public class Safelock {
static class Friend {
    private final String name;
    private final Lock lock = new ReentrantLock();

    public Friend(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public boolean impendingBow(Friend bower) {
        Boolean myLock = false;
        Boolean yourLock = false;
        try {
            myLock = lock.tryLock();
            yourLock = bower.lock.tryLock();
        } finally {
            if (! (myLock && yourLock)) {
                if (myLock) {
                    lock.unlock();
                }
                if (yourLock) {
                    bower.lock.unlock();
                }
            }
        }
        return myLock && yourLock;
    }

    public void bow(Friend bower) {
        if (impendingBow(bower)) {
            try {
                System.out.format("%s: %s has"
                    + " bowed to me!%n", 
                    this.name, bower.getName());
                bower.bowBack(this);
            } finally {
                lock.unlock();
                bower.lock.unlock();
            }
        } else {
            System.out.format("%s: %s started"
                + " to bow to me, but saw that"
                + " I was already bowing to"
                + " him.%n",
                this.name, bower.getName());
        }
    }

    public void bowBack(Friend bower) {
        System.out.format("%s: %s has" +
            " bowed back to me!%n",
            this.name, bower.getName());
    }
}

static class BowLoop implements Runnable {
    private Friend bower;
    private Friend bowee;

    public BowLoop(Friend bower, Friend bowee) {
        this.bower = bower;
        this.bowee = bowee;
    }

    public void run() {
        Random random = new Random();
        for (;;) {
            try {
                Thread.sleep(random.nextInt(10));
            } catch (InterruptedException e) {}
            bowee.bow(bower);
        }
    }
}


public static void main(String[] args) {
    final Friend alphonse =
        new Friend("Alphonse");
    final Friend gaston =
        new Friend("Gaston");
    new Thread(new BowLoop(alphonse, gaston)).start();
    new Thread(new BowLoop(gaston, alphonse)).start();
}

}

Мой вопрос - предположительно, поток 1 - поток alphanso и поток 2 - поток гастона выполняется все время с одинаковой скоростью. Таким образом, они будут вызывать impendingBow () вместе. Они оба пытаются получить блокировку самого себя и другого объекта, и если какая-либо из блокировок недоступна, они снимают полученную блокировку, если таковая имеется. Теперь, если оба потока исполняют строки с одинаковой скоростью, поток Alphanso сможет получить блокировку сам по себе, как и гастон, но оба не получат блокировку других, поскольку они были получены сами. Теперь согласно коду оба они освободят свою собственную блокировку (так как они не могли получить блокировку других.) И вернут false из impendingBow (), и оба выведут

else {
        System.out.format("%s: %s started"
            + " to bow to me, but saw that"
            + " I was already bowing to"
            + " him.%n",
            this.name, bower.getName());
    }

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

1 Ответ

0 голосов
/ 27 апреля 2018

Класс BowLoop имеет бесконечный цикл со случайной задержкой (Thread.sleep(random.nextInt(10));), которая предотвращает описанный вами сценарий. Обычной практикой является использование случайной задержки перед повторной попыткой получить блокировки после освобождения в случае «столкновений».

...