Основная проблема в данном коде — некорректное использование блокировки ReentrantLock. В методе incrementBins() вызывается lock.lock(), но отсутствует вызов lock.unlock() в блоке finally, что приводит к тому, что блокировка никогда не снимается. В результате при первом вызове блокировки поток захватывает lock и никогда не освобождает его, вызывая блокировку остальных потоков и потенциальный дедлок.
ReentrantLock в Java: забытый unlock и блокировка потоков
Основная проблема в данном коде — некорректное использование блокировки ReentrantLock.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
В чём основная проблема данной реализации
- Неэффективное использование фиксированного пула потоков
- Проблемы с взаимодействием общих ресурсов
- Некорректное включение блокировки может привести к тупиковой ситуации.
- Некорректный уровень синхронизации
- Нет проверок всех потоков перед результатом
- Нет явного конструктора
Код:
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
class RecyclingBinCounter { private int binCount; private final ReentrantLock lock = new ReentrantLock();
public void incrementBins() {
lock.lock();
try {
binCount++;
} finally {
}
}
public int getBinCount() {
return binCount;
}
}
class RecyclingManager { public static void main(String[] args) { RecyclingBinCounter counter = new RecyclingBinCounter(); ExecutorService service = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) {
service.submit(() -> {
for (int j = 0; j < 1000; j++) {
counter.incrementBins();
}
});
}
service.shutdown();
while(!service.isTerminated()) {}
System.out.println("Total bins collected: " + counter.getBinCount());
}
}
Ответ
Основная проблема в данном коде — некорректное использование блокировки ReentrantLock. В методе incrementBins() вызывается lock.lock(), но отсутствует вызов lock.unlock() в блоке finally, что приводит к тому, что блокировка никогда не снимается. В результате при первом вызове блокировки поток захватывает lock и никогда не освобождает его, вызывая блокировку остальных потоков и потенциальный дедлок.
Правильный вариант:
public void incrementBins() {
lock.lock();
try {
binCount++;
} finally {
lock.unlock();
}
}
Дополнительно:
- В main после service.shutdown() лучше использовать service.awaitTermination() с таймаутом вместо пустого цикла while(!service.isTerminated()) {}, чтобы избежать активного ожидания.
- Можно добавить конструктор в RecyclingBinCounter для инициализации binCount, хотя это не критично.
- Уровень синхронизации корректен, но без unlock блокировка не работает.
Итог: отсутствие вызова lock.unlock() в finally — главная ошибка, приводящая к блокировке потоков и неправильной работе программы.