Використання Semaphore у Java
Семафор у Java є засобом синхронізації, який регулює кількість потоків, які можуть одночасно отримувати доступ до
спільного ресурсу. Він є частиною пакету java.util.concurrent
і зазвичай використовується
для контролю доступу до ресурсів з обмеженою кількістю дозволів, таких як з’єднання з базою даних або мережеві сокети.
Основні особливості Semaphore
- Дозволи: Семафор підтримує набір дозволів, і потоки отримують дозволи для продовження роботи і звільняють їх, коли робота завершена.
- Блокуюче та неблокуюче отримання: Потоки можуть чекати, поки дозвіл стане доступним, або намагатися отримати дозвіл без блокування.
- Справедливість: Семафори можуть бути справедливими або несправедливими. Справедливі семафори надають дозволи в порядку, в якому вони були запитані.
Базове використання 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(); // Звільнення дозволу
}
}
}
}
У цьому прикладі:
- Ініціалізація: Створюється семафор з 3 дозволами.
- Реалізація завдання: Клас Task реалізує Runnable і намагається отримати дозвіл перед продовженням роботи. Якщо дозвіл доступний, потік отримує його і імітує деяку роботу. Після завершення роботи потік звільняє дозвіл.
- Виконання потоків: Запускаються десять потоків, але одночасно тільки три з них можуть мати дозвіл, таким чином, тільки три потоки можуть виконувати критичну секцію одночасно.
Розширене використання Semaphore
- Спроба отримати дозвіл без блокування:
if (semaphore.tryAcquire()) { try { // Критична секція } finally { semaphore.release(); } } else { System.out.println(Thread.currentThread().getName() + " не зміг отримати дозвіл."); }
- Отримання дозволу з тайм-аутом:
if (semaphore.tryAcquire(1, TimeUnit.SECONDS)) { try { // Критична секція } finally { semaphore.release(); } } else { System.out.println(Thread.currentThread().getName() + " перевищив час очікування дозволу."); }
- Справедливі семафори:
Semaphore fairSemaphore = new Semaphore(MAX_PERMITS, true);
Використання Semaphore
- Обмеження швидкості: Контроль кількості одночасного доступу до ресурсу.
- Пул з’єднань: Управління доступом до пулу з’єднань з базою даних.
- Управління ресурсами: Обмеження доступу до обмеженої кількості ресурсів, таких як принтери або файлові дескриптори.
Висновок
Семафори в Java забезпечують надійний механізм для контролю доступу до спільних ресурсів, особливо коли потрібно обмежити кількість одночасних доступів. Розуміючи, як ефективно використовувати семафори, ви можете забезпечити ефективне управління ресурсами у ваших багатопотокових додатках і уникнути проблем з конкуренцією.