senior
Напишите простейший многопоточный ограниченный буфер с использованием synchronized
Ограниченный буфер (bounded buffer) — это классическая задача «производитель-потребитель» с фиксированной ёмкостью.
Код: кольцевой буфер на synchronized
class QueueSynchronized<T> {
private volatile int size = 0;
private final Object[] content;
private final int capacity;
private int out; // Индекс для извлечения
private int in; // Индекс для вставки
private final Object isEmpty = new Object(); // Монитор «пусто»
private final Object isFull = new Object(); // Монитор «полно»
QueueSynchronized(final int capacity) {
this.capacity = capacity;
content = new Object[this.capacity];
out = 0;
in = 0;
size = 0;
}
private int cycleInc(int index) {
return (++index == capacity) ? 0 : index;
}
@SuppressWarnings("unchecked")
T get() throws InterruptedException {
if (size == 0) {
synchronized (isEmpty) {
while (size < 1) {
isEmpty.wait(); // Ждём, пока буфер не станет непустым
}
}
}
try {
synchronized (this) {
final Object value = content[out];
content[out] = null;
if (size > 1) {
out = cycleInc(out);
}
size--;
return (T) value;
}
} finally {
synchronized (isFull) {
isFull.notify(); // Уведомляем производителя, что появилось место
}
}
}
QueueSynchronized<T> put(T value) throws InterruptedException {
if (size == capacity) {
synchronized (isFull) {
while (size == capacity) {
isFull.wait(); // Ждём, пока буфер не освободится
}
}
}
synchronized (this) {
if (size == 0) {
content[in] = value;
} else {
in = cycleInc(in);
content[in] = value;
}
size++;
}
synchronized (isEmpty) {
isEmpty.notify(); // Уведомляем потребителя, что появился элемент
}
return this;
}
}
Ключевые моменты реализации:
- Используется кольцевой буфер (circular buffer) — индексы
inиoutоборачиваются черезcycleInc. - Два отдельных монитора (
isEmpty,isFull) позволяют производителю и потребителю ожидать независимо. - Цикл
whileвwait()— защита от ложных пробуждений (spurious wakeup).
На собеседовании стоит отметить, что в продакшене вместо ручной реализации используют
ArrayBlockingQueueиз JDK, который реализует ту же логику, но черезReentrantLock+Condition.