Проблема в том, что вы используете queue.notify (), которая будет пробуждать только один поток, ожидающий в очереди. Imagine Producer 1 вызывает notify () и запускает Producer 2. Producer 2 видит, что в очереди что-то есть, поэтому он ничего не производит и просто возвращается к вызову wait (). Теперь и ваши Производители, и Потребители все ждут, чтобы их уведомили, и никто не остался работать, чтобы уведомить кого-либо.
Чтобы решить проблему в вашем коде, используйте queue.notifyAll (), чтобы активировать каждый поток, заблокированный в wait (). Это позволит вашим потребителям работать.
Как примечание, ваша реализация ограничивает очередь не более чем одним элементом в ней. Таким образом, вы не увидите никакой выгоды от второго набора производителей и потребителей. Для более полной реализации, я предлагаю вам взглянуть на BlockingQueue и использовать реализацию, которая может быть ограничена, например, ArrayBlockingQueue . Вместо синхронизации и использования wait / notify, просто используйте BlockingQueue.offer () и BlockingQueue.take () .