Semaphore — это просто счетчик одновременных доступов.
Допустим, у нас есть база данных. Мы точно знаем: если в нее одновременно полезет больше 10 потоков, она ляжет.
В этом случае мы создаем семафор на 10 мест:
Semaphore semaphore = new Semaphore(10);
В коде задачи это выглядит так:
try {
semaphore.acquire(); // Занимаем одно место из десяти
// Работаем с базой данных
queryDatabase();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release(); // Освобождаем место
}
Как это работает:
Пока в базе работают меньше 10 потоков, acquire() пропускает задачу мгновенно. Как только их становится ровно 10, одиннадцатый поток останавливается прямо на строчке acquire(). Он не крутит цикл и не жрет процессор, он просто спит.
Когда любой из работающих десяти вызовут release(), спящий тут же проснется и займет освободившееся место.