Похоже на простой случай голодания. Рассмотрим основной писатель l oop:
while (j != 5){
data.writeQ(i++);
// i++;
j++;
}
data.writeQ()
- это метод synchronized
: самое последнее, что он делает перед возвратом, это разблокирует блокировку. Самое первое, что он делает при следующем вызове, это повторно блокирует блокировку. Между ними мало что происходит - инкремент и проверка локальной переменной - это все.
Java synchronized
блокировки не справедливые . (то есть, когда блокировка становится доступной, система не гарантирует, что победителем будет тот поток, который ждал дольше всего.) Фактически, это может быть напротив Справедливо: ОС может попытаться максимизировать эффективное использование ЦП, всегда выбирая поток, который легче всего активизировать.
Когда писатель возвращается к вызову data.writeQ()
на каждой последующей итерации, он может будь то, что ОС даже не запустила запустил , чтобы разбудить читателя, и просто позволяет автору снова войти в блок synchronized
.
То же самое происходит с вашим читателем , Код немного сложнее, но, как и в писателе, самое последнее, что data.readQ()
делает перед возвратом, это разблокирует блокировку, и самое первое, что он делает при следующем вызове, - это снова блокирует его.
Решение методом грубой силы: замените блоки synchronized
на справедливый ReentrantLock
объект.
Альтернативное решение, более типично для того, сколько программ на самом деле работает: пусть потоки делают что-то еще (например, заставляют их выполнять некоторые операции ввода-вывода) между вызовами заблокированной функции, тем самым давая другим потокам возможность войти в и использовать заблокированный ресурс.