Семафор в Java
Semaphore хранит число разрешений. acquire() забирает разрешение или ждет, release() возвращает. Это удобно для ограничения параллельного доступа к внешнему ресурсу.
final class LimitedClient {
private final Semaphore permits = new Semaphore(8, true);
Response call(Request request) throws InterruptedException {
permits.acquire();
try {
return remoteCall(request);
} finally {
permits.release();
}
}
}finally не дает утечь разрешению. Но release() нужно выполнять только после успешного acquire():
boolean acquired = permits.tryAcquire(200, TimeUnit.MILLISECONDS);
if (!acquired) throw new TimeoutException();
try {
useResource();
} finally {
permits.release();
}Важные свойства
- семафор с N permits допускает до N участников;
- он не отслеживает владельца: технически один поток может сделать
release()за другой; - fairness
trueуменьшает обгон ожидающих, но может снизить throughput; availablePermits()— диагностический снимок, не основание для «check then act»;- семафор ограничивает конкуренцию, но не делает сам ресурс потокобезопасным.
Для пула конкретных объектов одной семафоры мало: нужна еще потокобезопасная очередь ресурсов. Для одного владельца понятнее Mutex/Lock.
На собеседовании
- Чем semaphore отличается от mutex? Считает N разрешений и не имеет строгого владельца.
- Что произойдет при забытом
release()? Разрешение утечет, система постепенно остановится. - Гарантирует ли fair semaphore строгий порядок во всех методах? Нет абсолютной гарантии для untimed
tryAcquire. - Делает ли semaphore объект thread-safe? Нет, только ограничивает число одновременных пользователей.