Если поток блокируется до тех пор, пока он не сможет читать или добавлять в очередь, лучшее место для него - это набор ожидания для применимого условия.Таким образом, он не борется активно за блокировку и не переключается в контекст.
Если в очередь добавляется только один элемент, мы хотим сообщить об этом только одному потребителю.Мы не хотим сигнализировать большему количеству потребителей, чем у нас есть элементы в очереди, потому что это заставляет систему работать и управлять временными интервалами для всех потоков, которые не могут прогрессировать независимо.
Вот почему ArrayBlockingQueue сигнализирует по одному за каждый раз, когда элемент ставится в очередь или удаляется из очереди, чтобы избежать ненужных пробуждений.В вашей реализации все в waitset просыпаются при переходе (от пустого к непустому или от полного к не полному), независимо от того, сколько из этих потоков сможет выполнить свою работу.
Это становится более значительным, так как большее количество потоков сталкивается с этим одновременно.Представьте себе систему с 100 потоками, ожидающими что-то из очереди, но каждые 10 секунд добавляется только один элемент.Было бы лучше не выбрасывать 100 потоков из waitset, чтобы 99 из них вернулись.