Синхронизированные (экземплярные) методы блокируют объект, а НЕ класс.
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), то тупиковая ситуация не возникнет.