Вы не делаете ничего явно неправильного с вызовами метода, но у вас есть условие гонки .
Хотя в идеальном мире главный поток все равно достигнет своего синхронизированного блокарабочие потоки достигают вызова wait (), нет гарантии того, что (вы явно сказали виртуальной машине, что не хотите, чтобы потоки выполнялись последовательно с основным потоком, сделав их потоками),Может случиться (например, если у вас только одно ядро), что планировщик потока решит заблокировать все рабочие потоки сразу, как только они начнут, чтобы основной поток продолжил работу.Может случиться так, что рабочие потоки отключены из-за отсутствия кэша.Может случиться так, что один рабочий поток блокирует ввод / вывод (оператор print), и основной поток включается на его место.
Таким образом, если основной поток успевает достичь синхронизированного блока раньше всего рабочегопотоки достигли вызова wait (), те рабочие потоки, которые не достигли вызова wait (), не будут работать должным образом.Поскольку текущая настройка не позволяет вам управлять этим, вы должны добавить явную обработку этого.Вы можете либо добавить какую-то переменную, которая увеличивается, когда каждый рабочий поток достигает wait (), и чтобы основной поток не вызывал notifyAll () до тех пор, пока эта переменная не достигнет 5, либо вы можете иметь цикл основного потока и многократно вызывать notifyAll (),так что рабочие потоки выпускаются в нескольких группах.
Посмотрите в пакете java.util.concurrent
- есть несколько классов блокировки, которые предоставляют более мощные возможности, чем базовые синхронизированные блокировки - как всегда, Java избавляет вас от повторного использования.изобретать колесо. CountDownLatch может показаться особенно уместным.
Таким образом, параллелизм составляет hard .Вы должны спроектировать, чтобы убедиться, что все работает, когда потоки выполняются в нежелательных вами порядках, а также в тех, которые вам нужны.