Оба ожидающих потока получают уведомление. Обе ожидающие темы просыпаются внутри цикла. Оба должны проверить условие, чтобы выйти из цикла. Но один из ожидающих потоков пойдет первым и захлопнет дверь другого.
Когда ожидающий поток получает уведомление, он все еще находится в методе ожидания, он не может покинуть метод ожидания, пока не получит блокировку. (Помните, что ожидание находится внутри синхронизированного метода, и поток снял блокировку на объекте ShareResource, когда он начал ждать.) Конечно, только один поток может получить блокировку одновременно.
Из двух уведомленных потоков первый, кто получит блокировку, выйдет из метода ожидания, затем проверит условие цикла. Он находит, что n равно 0, и может выйти из цикла. Тогда поток увеличивает n. Все это происходит при удерживаемой блокировке, поэтому никакие другие потоки не могут вмешиваться.
Все это время второй поток был заблокирован; он был разбужен тем же уведомлением, что и первый поток, но не смог получить блокировку. Как только первый поток вышел из метода p, сняв блокировку, второй поток может взять блокировку и выйти из метода ожидания. В этот момент он проверяет условие цикла while, обнаруживает, что n больше 0 благодаря первому потоку, затем снова входит в метод wait и возвращается туда, где он начался.
Обратите внимание, что notifyAll, как правило, расточительно, потому что пробуждаются несколько потоков, но только один может добиться прогресса.