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