Вопрос о тупике от Солнца учебники - PullRequest
7 голосов
/ 16 февраля 2010

Ниже приведен код непосредственно из учебных пособий Sun, описывающих тупик. Однако я не понимаю, как может возникнуть тупик в этой ситуации, учитывая, что оба метода синхронизированы. Как два потока будут находиться в одном и том же синхронизированном методе одновременно?

Deadlock описывает ситуацию, когда два или более потоков заблокированы навсегда, ожидая друг друга. Вот пример.

Альфонс и Гастон - друзья и великие сторонники вежливости. Строгое правило вежливости заключается в том, что когда вы кланяетесь другу, вы должны оставаться в поклоне, пока у вашего друга не появится шанс вернуть лук. К сожалению, это правило не учитывает вероятность того, что два друга могут поклониться друг другу одновременно. В этом примере приложения Deadlock моделируется такая возможность:

public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s has bowed to me!%n", 
                    this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s has bowed back to me!%n",
                    this.name, bower.getName());
        }
    }

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

Когда работает Deadlock, очень вероятно, что оба потока будут блокироваться при попытке вызвать bowBack. Ни один блок никогда не закончится, потому что каждый поток ожидает, когда другой выйдет из лука.

1 Ответ

8 голосов
/ 16 февраля 2010

Синхронизированные (экземплярные) методы блокируют объект, а НЕ класс.

alphonse.bow захватывает блокировку на alphonse и gaston.bow захватывает блокировку на gaston. Когда нить 'alphonse' находится в поклоне, она пытается захватить блокировку 'gaston' в bower.bowBack. Аналогично, «гастон» пытается захватить «альфонс».

Изменить для ясности (надеюсь):

Давайте назовем два потока Thread1 и Thread2.

Thread1 запускает alphonse.bow (gaston), где он захватывает блокировку на объекте alphonse, а Thread2 запускает gaston.bow (alphonse) и захватывает блокировку на объекте gaston.

В Thread1, когда он пытается запустить bower.bowBack (this), где bower = gaston, поток должен сначала получить блокировку на gaston.

Пока это происходит, Thread2 пытается сделать то же самое, с bower = alphonse. Thread1 имеет блокировку, необходимую для Thread2, и наоборот, поэтому возникает взаимоблокировка.

Кроме того, тупик не всегда должен возникать. Если Thread1 может начаться и завершиться до того, как Thread2 сможет это сделать (например, если что-то зависнет в основном потоке после запуска Thread1, но до создания / запуска Thread2), то тупиковая ситуация не возникнет.

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