Примеры семафоров Java
В Java мы можем использоватьSemaphore
, чтобы ограничить количество потоков для доступа к определенному ресурсу.
1. Что такое семафор?
Короче говоря, семафор поддерживает набор разрешений (билетов), каждыйacquire()
будет принимать разрешение (билет) из семафора, каждыйrelease()
вернет разрешение (билет) обратно семафору. Если разрешения (билеты) недоступны,acquire()
будет заблокирован, пока он не станет доступен.
// 5 tickets Semaphore semaphore = new Semaphore(5); // take 1 ticket semaphore.acquire(); // 4 semaphore.availablePermits(); // return back ticket semaphore.release(); // 5 semaphore.availablePermits();
2. Семафор Java
Пример Java Semaphore для ограничения количества задач, выполняемых вExecutorService
. В этом примере 5Callable
задач отправляются вExecutorService
, но только 2 задачи выполняются одновременно.
TaskLimitSemaphore.java
package com.example.concurrency.synchronizer.semaphore; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.*; // Throttle task submission public class TaskLimitSemaphore { private final ExecutorService executor; private final Semaphore semaphore; public TaskLimitSemaphore(ExecutorService executor, int limit) { this.executor = executor; this.semaphore = new Semaphore(limit); } publicFuture submit(final Callable task) throws InterruptedException { semaphore.acquire(); System.out.println("semaphore.acquire()..."); return executor.submit(() -> { try { return task.call(); } finally { semaphore.release(); System.out.println("semaphore.release()..."); } }); } private static final DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newCachedThreadPool(); // Only 2 tasks are able to run concurrently TaskLimitSemaphore obj = new TaskLimitSemaphore(executor, 2); obj.submit(() -> { System.out.println(getCurrentDateTime() + " : task1 is running!"); Thread.sleep(2000); System.out.println(getCurrentDateTime() + " : task1 is done!"); return 1; }); obj.submit(() -> { System.out.println(getCurrentDateTime() + " : task2 is running!"); Thread.sleep(2000); System.out.println(getCurrentDateTime() + " task2 is done!"); return 2; }); obj.submit(() -> { System.out.println(getCurrentDateTime() + " task3 is running!"); Thread.sleep(2000); System.out.println(getCurrentDateTime() + " task3 is done!"); return 3; }); obj.submit(() -> { System.out.println(getCurrentDateTime() + " task4 is running!"); Thread.sleep(2000); System.out.println(getCurrentDateTime() + " task4 is done!"); return 4; }); obj.submit(() -> { System.out.println(getCurrentDateTime() + " task5 is running!"); Thread.sleep(2000); System.out.println(getCurrentDateTime() + " task5 is done!"); return 5; }); executor.shutdown(); } private static String getCurrentDateTime() { return sdf.format(new Date()); } }
Выход
semaphore.acquire()... semaphore.acquire()... 2018/12/06 18:45:22 : task1 is running! 2018/12/06 18:45:22 : task2 is running! 2018/12/06 18:45:24 : task1 is done! 2018/12/06 18:45:24 task2 is done! semaphore.release()... semaphore.acquire()... semaphore.release()... semaphore.acquire()... 2018/12/06 18:45:24 task3 is running! 2018/12/06 18:45:24 task4 is running! 2018/12/06 18:45:26 task4 is done! 2018/12/06 18:45:26 task3 is done! semaphore.acquire()... semaphore.release()... semaphore.release()... 2018/12/06 18:45:26 task5 is running! 2018/12/06 18:45:28 task5 is done! semaphore.release()...
3. Mutex
Короче говоря, всегдаnew Semaphore(1)
, только одному потоку разрешен доступ к определенному ресурсу.
PrintSequenceCallable.java
package com.example.concurrency.synchronizer.semaphore; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class SshLoginSemaphore { private final Semaphore mutex; // only 1 user is allow public SshLoginSemaphore() { this.mutex = new Semaphore(1); } private void ssh(String user) throws InterruptedException { mutex.acquire(); System.out.println(getCurrentDateTime() + " : " + user + " mutex.acquire()"); Thread.sleep(2000); mutex.release(); System.out.println(getCurrentDateTime() + " : " + user + " mutex.release()"); } private static final DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(5); SshLoginSemaphore task = new SshLoginSemaphore(); // submit 3 tasks executor.submit(() -> { try { task.ssh("example"); } catch (InterruptedException e) { e.printStackTrace(); } }); executor.submit(() -> { try { task.ssh("yflow"); } catch (InterruptedException e) { e.printStackTrace(); } }); executor.submit(() -> { try { task.ssh("zilap"); } catch (InterruptedException e) { e.printStackTrace(); } }); executor.shutdown(); } private static String getCurrentDateTime() { return sdf.format(new Date()); } }
Выход
Просмотрите время (секунды), разрешен только один поток, одинacquire()
с и одинrelease()
с
2018/12/06 18:54:25 : example mutex.acquire() 2018/12/06 18:54:27 : yflow mutex.acquire() 2018/12/06 18:54:27 : example mutex.release() 2018/12/06 18:54:29 : zilap mutex.acquire() 2018/12/06 18:54:29 : yflow mutex.release() 2018/12/06 18:54:31 : zilap mutex.release()
Скачать исходный код
$ git clone https://github.com/example/java-concurrency.git