Використання Semaphore у Java

Published June 20, 2024

Використання Semaphore у Java

Семафор у Java є засобом синхронізації, який регулює кількість потоків, які можуть одночасно отримувати доступ до спільного ресурсу. Він є частиною пакету java.util.concurrent і зазвичай використовується для контролю доступу до ресурсів з обмеженою кількістю дозволів, таких як з’єднання з базою даних або мережеві сокети.

Основні особливості Semaphore

  1. Дозволи: Семафор підтримує набір дозволів, і потоки отримують дозволи для продовження роботи і звільняють їх, коли робота завершена.
  2. Блокуюче та неблокуюче отримання: Потоки можуть чекати, поки дозвіл стане доступним, або намагатися отримати дозвіл без блокування.
  3. Справедливість: Семафори можуть бути справедливими або несправедливими. Справедливі семафори надають дозволи в порядку, в якому вони були запитані.

Базове використання Semaphore

Ось простий приклад, що демонструє використання Semaphore:

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
   private static final int MAX_PERMITS = 3;
   private static final Semaphore semaphore = new Semaphore(MAX_PERMITS);

   public static void main(String[] args) {
      for (int i = 0; i < 10; i++) {
         new Thread(new Task()).start();
      }
   }

   static class Task implements Runnable {
      @Override
      public void run() {
         try {
            System.out.println(Thread.currentThread().getName() + " чекає на дозвіл.");
            semaphore.acquire();  // Отримання дозволу
            System.out.println(Thread.currentThread().getName() + " отримав дозвіл.");

            // Імітація роботи з спільним ресурсом
            Thread.sleep(2000);

            System.out.println(Thread.currentThread().getName() + " звільняє дозвіл.");
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            semaphore.release();  // Звільнення дозволу
         }
      }
   }
}

У цьому прикладі:

  1. Ініціалізація: Створюється семафор з 3 дозволами.
  2. Реалізація завдання: Клас Task реалізує Runnable і намагається отримати дозвіл перед продовженням роботи. Якщо дозвіл доступний, потік отримує його і імітує деяку роботу. Після завершення роботи потік звільняє дозвіл.
  3. Виконання потоків: Запускаються десять потоків, але одночасно тільки три з них можуть мати дозвіл, таким чином, тільки три потоки можуть виконувати критичну секцію одночасно.

Розширене використання Semaphore

  1. Спроба отримати дозвіл без блокування:
    if (semaphore.tryAcquire()) {
        try {
            // Критична секція
        } finally {
            semaphore.release();
        }
    } else {
        System.out.println(Thread.currentThread().getName() + " не зміг отримати дозвіл.");
    }
    
  2. Отримання дозволу з тайм-аутом:
    if (semaphore.tryAcquire(1, TimeUnit.SECONDS)) {
        try {
            // Критична секція
        } finally {
            semaphore.release();
        }
    } else {
        System.out.println(Thread.currentThread().getName() + " перевищив час очікування дозволу.");
    }
    
  3. Справедливі семафори:
    Semaphore fairSemaphore = new Semaphore(MAX_PERMITS, true);
    

Використання Semaphore

  1. Обмеження швидкості: Контроль кількості одночасного доступу до ресурсу.
  2. Пул з’єднань: Управління доступом до пулу з’єднань з базою даних.
  3. Управління ресурсами: Обмеження доступу до обмеженої кількості ресурсів, таких як принтери або файлові дескриптори.

Висновок

Семафори в Java забезпечують надійний механізм для контролю доступу до спільних ресурсів, особливо коли потрібно обмежити кількість одночасних доступів. Розуміючи, як ефективно використовувати семафори, ви можете забезпечити ефективне управління ресурсами у ваших багатопотокових додатках і уникнути проблем з конкуренцією.