Sobes.tech
Назад к вопросам
Junior — Middle
54

Какая роль у семафора в управлении доступом к ресурсам в многопоточном программировании?

Ответ от нейросети

sobes.tech AI

Что хотят услышать интервьюеры:

Семафор ограничивает число потоков, которые могут одновременно войти в критическую секцию или использовать общий ресурс. Он помогает не просто защищать данные, как mutex, а именно контролировать количество одновременных доступов. В Java это удобно для пула ресурсов, соединений или ограниченных внешних сервисов.

Определение:

Семафор — это синхронизатор, который хранит счётчик доступных разрешений. Поток должен получить разрешение перед использованием ресурса и освободить его после завершения работы. Если разрешений нет, поток блокируется до их появления.

В Java семафор обычно используют через java.util.concurrent.Semaphore.

Пример использования:

Допустим, есть база данных с максимум 3 одновременными соединениями. Даже если в приложение пришло 20 потоков, только 3 из них смогут работать с БД одновременно.

import java.util.concurrent.Semaphore;

public class DatabaseAccess {
    private final Semaphore semaphore = new Semaphore(3);

    public void query(String sql) throws InterruptedException {
        semaphore.acquire();
        try {
            System.out.println(Thread.currentThread().getName() + " выполняет запрос: " + sql);
            Thread.sleep(1000);
        } finally {
            semaphore.release();
        }
    }
}

Пояснение кода:

  1. Создаётся семафор с 3 разрешениями: new Semaphore(3).
  2. Перед выполнением запроса поток вызывает acquire().
  3. Если одно из разрешений доступно, поток продолжает работу; если нет — ждёт.
  4. После завершения работы в блоке finally вызывается release(), чтобы вернуть разрешение.
  5. finally важен, потому что разрешение должно освобождаться даже при ошибке.

Ключевые моменты:

  • Семафор управляет количеством одновременных доступов, а не только взаимным исключением.
  • Это подходящий инструмент для ограничения нагрузки на ресурс: пул соединений, очередь задач, лимит API.
  • В Java семафор может быть справедливым или несправедливым по очереди ожидания, но по умолчанию порядок может не гарантироваться.
  • acquire() блокирует поток при отсутствии разрешений, release() возвращает разрешение.
  • Если семафор используется неправильно и release() не вызывается, можно получить “утечку” разрешений и зависание потоков.
  • Для защиты данных от гонок семафор не всегда лучший выбор; для этого чаще подходит synchronized или Lock.