Exemples de sémaphore Java
En Java, nous pouvons utiliserSemaphore
pour limiter le nombre de threads pour accéder à une certaine ressource.
1. Qu'est-ce que le sémaphore?
En bref, un sémaphore maintient un ensemble de permis (tickets), chaqueacquire()
prendra un permis (ticket) du sémaphore, chaquerelease()
retournera le permis (ticket) au sémaphore. Si les permis (tickets) ne sont pas disponibles,acquire()
bloquera jusqu'à ce qu'il y en ait un.
// 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 Semaphore
Un exemple de sémaphore Java pour limiter le nombre de tâches en cours d'exécution dansExecutorService
. Dans cet exemple, 5 tâchesCallable
sont soumises àExecutorService
, mais seules 2 tâches sont exécutées simultanément.
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()); } }
Sortie
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
En bref, toujoursnew Semaphore(1)
, un seul thread est autorisé à accéder à une certaine ressource.
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()); } }
Sortie
Vérifiez le temps (secondes), un seul thread est autorisé, unacquire()
et unrelease()
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()
Télécharger le code source
$ git clone https://github.com/example/java-concurrency.git