Advanced Java Services | Semaphor |
Das Wort Semaphor (das oder der Semaphore, Plural die Semaphore) kommt aus dem Griechischen, und heißt wörtlich übersetzt Zeichenträger. Übliche Übersetzungen sind Signal, Signalgeber oder Ampel. In der Informatik bedeutet Semaphor eine Kontrollinstanz, die sicherstellt, daß nur eine bestimmte Anzahl von Threads auf ein Objekt bzw, Resource zugreifen können. In Java wird diese Kontrollinstanz durch die von Doug Lea entwickelte Klasse java.util.concurrent.Semaphore realisiert (ab Java 1.5).
Ein Semaphor erlaubt einer festen und damit begrenzten Anzahl an Threads eine Resource zu verwenden (kritischer Abschnitt). Die Threads können sich während der Laufzeit ändern. Jeder Thread muß eine Erlaubnis einholen. Ist die maximale Anzahl erreicht, gibt es keine Erlaubnis mehr bis ein zugelassener Thread seine Arbeit beendet hat. Das Semaphor verwaltet intern eine Menge sogenannter Erlaubnisse (engl. permits).
Im folgenden gibt es einen Worker, der eine Ausgabe auf die Konsole machen will. Diese dauert unterschiedlich lange. Jeder Worker muß dazu die Erlaubnis von einer Semaphor erhalten. Es dürfen maximal 3 Worker die Konsole benutzen. Jeder Worker will die Konsole 5-mal verwenden. Jeder Worker zeigt an, zum wievielten Male er die Konsole verwendet. Es werden 5 Worker angelegt.
Der Worker
package hms; import java.util.Random; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; /** */ public class Worker implements Runnable { private Random rd = new Random(); private Semaphore semaphore; public Worker(Semaphore semaphore) { this.semaphore = semaphore; } @Override public void run() { boolean acquired = false; for(int i = 0; i < 5; i++) { try { semaphore.acquire(); acquired = true; System.out.print(Thread.currentThread().getName() + " #" + i + " : "); System.out.println("remaining Permits :" + semaphore.availablePermits()); TimeUnit.MILLISECONDS.sleep(500 + rd.nextInt(2500)); System.out.println(Thread.currentThread().getName() + " #" + i + " : leaving"); } catch(InterruptedException e) { break; } finally { if (acquired) semaphore.release(); } } } }
Main
package hms; import java.util.concurrent.Semaphore; public class Semaphor_1 { public static void main(String[] args) { System.out.println("Semaphor_1"); Semaphore semaphore = new Semaphore(3); //Semaphore semaphore = new Semaphore(3, true); System.out.println("is fair : " + semaphore.isFair()); System.out.println(); Worker[] workers = new Worker[5]; for(int i=0; i < workers.length; i++) workers[i] = new Worker(semaphore); for(int i=0; i < workers.length; i++) new Thread(workers[i]).start(); } }
Eine mögliche Ausgabe (nicht fair)
is fair : false Thread-0 #0 : remaining Permits :2 Thread-1 #0 : remaining Permits :1 Thread-2 #0 : remaining Permits :0 Thread-2 #0 : leaving Thread-2 #1 : remaining Permits :0 Thread-0 #0 : leaving Thread-0 #1 : remaining Permits :0 Thread-1 #0 : leaving Thread-1 #1 : remaining Permits :0 Thread-2 #1 : leaving Thread-2 #2 : remaining Permits :0 Thread-1 #1 : leaving Thread-1 #2 : remaining Permits :0 Thread-0 #1 : leaving Thread-0 #2 : remaining Permits :0 Thread-2 #2 : leaving Thread-2 #3 : remaining Permits :0 Thread-1 #2 : leaving Thread-1 #3 : remaining Permits :0 Thread-2 #3 : leaving Thread-2 #4 : remaining Permits :0 Thread-0 #2 : leaving Thread-0 #3 : remaining Permits :0 Thread-1 #3 : leaving Thread-1 #4 : remaining Permits :0 Thread-2 #4 : leaving Thread-3 #0 : remaining Permits :0 Thread-1 #4 : leaving Thread-4 #0 : remaining Permits :0 Thread-0 #3 : leaving Thread-0 #4 : remaining Permits :0 Thread-4 #0 : leaving Thread-4 #1 : remaining Permits :0 Thread-0 #4 : leaving Thread-3 #0 : leaving Thread-3 #1 : remaining Permits :1 Thread-4 #1 : leaving Thread-4 #2 : remaining Permits :1 Thread-3 #1 : leaving Thread-3 #2 : remaining Permits :1 Thread-3 #2 : leaving Thread-3 #3 : remaining Permits :1 Thread-4 #2 : leaving Thread-4 #3 : remaining Permits :1 Thread-3 #3 : leaving Thread-3 #4 : remaining Permits :1 Thread-4 #3 : leaving Thread-4 #4 : remaining Permits :1 Thread-3 #4 : leaving Thread-4 #4 : leaving
Eine mögliche Ausgabe (fair)
is fair : true Thread-0 #0 : Thread-1 #0 : remaining Permits :1 remaining Permits :1 Thread-2 #0 : remaining Permits :0 Thread-1 #0 : leaving Thread-3 #0 : remaining Permits :0 Thread-3 #0 : leaving Thread-4 #0 : remaining Permits :0 Thread-0 #0 : leaving Thread-1 #1 : remaining Permits :0 Thread-2 #0 : leaving Thread-3 #1 : remaining Permits :0 Thread-1 #1 : leaving Thread-0 #1 : remaining Permits :0 Thread-4 #0 : leaving Thread-2 #1 : remaining Permits :0 Thread-3 #1 : leaving Thread-1 #2 : remaining Permits :0 Thread-0 #1 : leaving Thread-4 #1 : remaining Permits :0 Thread-2 #1 : leaving Thread-3 #2 : remaining Permits :0 Thread-1 #2 : leaving Thread-0 #2 : remaining Permits :0 Thread-4 #1 : leaving Thread-2 #2 : remaining Permits :0 Thread-3 #2 : leaving Thread-1 #3 : remaining Permits :0 Thread-0 #2 : leaving Thread-4 #2 : remaining Permits :0 Thread-1 #3 : leaving Thread-3 #3 : remaining Permits :0 Thread-2 #2 : leaving Thread-0 #3 : remaining Permits :0 Thread-4 #2 : leaving Thread-1 #4 : remaining Permits :0 Thread-0 #3 : leaving Thread-2 #3 : remaining Permits :0 Thread-3 #3 : leaving Thread-4 #3 : remaining Permits :0 Thread-2 #3 : leaving Thread-0 #4 : remaining Permits :0 Thread-1 #4 : leaving Thread-3 #4 : remaining Permits :0 Thread-4 #3 : leaving Thread-2 #4 : remaining Permits :0 Thread-3 #4 : leaving Thread-4 #4 : remaining Permits :0 Thread-0 #4 : leaving Thread-2 #4 : leaving Thread-4 #4 : leaving