Ein Semaphor in Java ist eine Synchronisationshilfe, die die Anzahl der Threads einschränkt, die zu einem bestimmten Zeitpunkt auf eine gemeinsam genutzte Ressource zugreifen können. Es ist Teil des Pakets java.util.concurrent und wird zur Verwaltung des gleichzeitigen Zugriffs auf Ressourcen wie Dateien, Datenbanken oder Netzwerkverbindungen verwendet.
Ein Semaphor steuert den Zugriff auf eine festgelegte Anzahl von Genehmigungen. Jede Genehmigung stellt das Recht dar, auf eine bestimmte Ressource zuzugreifen. Das Semaphor verfolgt die Anzahl der verfügbaren Berechtigungen, die bestimmt, wie viele Threads gleichzeitig auf die Ressource zugreifen können.
Erlaubnis: Ein Token oder ein Ticket, das es einem Thread ermöglicht, mit dem Zugriff auf eine freigegebene Ressource fortzufahren.
Beim Erstellen eines Semaphors geben Sie die Anzahl der verfügbaren Genehmigungen an. Diese Zahl definiert, wie viele Threads gleichzeitig auf die Ressource zugreifen können.
Bevor ein Thread auf die Ressource zugreifen kann, muss er eine Genehmigung vom Semaphor erhalten. Dies geschieht mit der Methode acquire().
Acquire: Diese Methode wird aufgerufen, wenn ein Thread auf die Ressource zugreifen möchte. Wenn eine Genehmigung verfügbar ist, verringert das Semaphor die Anzahl der verfügbaren Genehmigungen und ermöglicht die Fortsetzung des Threads. Wenn keine Genehmigungen verfügbar sind, wird der Thread blockiert, bis eine Genehmigung verfügbar wird.
Blockierungsverhalten: Wenn keine Genehmigungen verfügbar sind, wird der Thread, der acquire() aufruft, blockiert (d. h. er wartet), bis ein anderer Thread eine Genehmigung freigibt.
Sobald ein Thread die Nutzung der Ressource beendet hat, sollte er die Genehmigung freigeben, um sie für andere Threads verfügbar zu machen. Dies geschieht mit der Methode release().
Release: Diese Methode erhöht die Anzahl der verfügbaren Genehmigungen. Wenn Threads auf eine Genehmigung warten, wird einer von ihnen entsperrt und darf die Genehmigung erhalten.
In Java gibt es zwei Arten von Semaphoren:
Um besser zu verstehen, wie Semaphoren funktionieren, schauen wir uns eine praktische Implementierung an. Wir erstellen ein einfaches Szenario, in dem mehrere Threads versuchen, auf eine begrenzte Ressource zuzugreifen.
import java.util.concurrent.Semaphore; public class SemaphoreDemo { // Creating a semaphore with 3 permits private static final Semaphore semaphore = new Semaphore(3); public static void main(String[] args) { // Creating and starting 6 threads for (int i = 1; i <= 6; i++) { new WorkerThread("Worker " + i).start(); } } static class WorkerThread extends Thread { private String name; WorkerThread(String name) { this.name = name; } @Override public void run() { try { System.out.println(name + " is trying to acquire a permit..."); // Acquiring the semaphore semaphore.acquire(); System.out.println(name + " acquired a permit."); // Simulating work by sleeping Thread.sleep(2000); System.out.println(name + " is releasing a permit."); } catch (InterruptedException e) { e.printStackTrace(); } finally { // Releasing the semaphore semaphore.release(); } } } }
In diesem Beispiel erstellen wir ein Semaphor mit drei Berechtigungen, was bedeutet, dass jeweils nur drei Threads auf den kritischen Abschnitt des Codes zugreifen können. Anschließend erstellen wir sechs Threads, die alle versuchen, eine Genehmigung zu erhalten. Sobald ein Thread eine Genehmigung erhält, simuliert er eine Arbeit, indem er zwei Sekunden lang schläft, bevor er die Genehmigung freigibt.
Wenn Sie den obigen Code ausführen, sieht die Ausgabe etwa so aus:
Worker 1 is trying to acquire a permit... Worker 1 acquired a permit. Worker 2 is trying to acquire a permit... Worker 2 acquired a permit. Worker 3 is trying to acquire a permit... Worker 3 acquired a permit. Worker 4 is trying to acquire a permit... Worker 5 is trying to acquire a permit... Worker 6 is trying to acquire a permit... Worker 1 is releasing a permit. Worker 4 acquired a permit. Worker 2 is releasing a permit. Worker 5 acquired a permit. Worker 3 is releasing a permit. Worker 6 acquired a permit.
Hier erhalten die ersten drei Threads erfolgreich die Genehmigungen und beginnen mit ihren Aufgaben. Die verbleibenden Threads müssen warten, bis eine Genehmigung freigegeben wird, bevor sie fortfahren können.
Semaphoren sind besonders nützlich in Szenarien, in denen Sie die Anzahl gleichzeitiger Zugriffe auf eine bestimmte Ressource begrenzen müssen, wie zum Beispiel:
Obwohl Semaphore ein leistungsstarkes Werkzeug sind, haben sie ihre eigenen Vor- und Nachteile.
Flexibilität: Semaphoren ermöglichen eine präzise Steuerung des Ressourcenzugriffs durch mehrere Threads.
Skalierbarkeit: Semaphore können den Zugriff auf eine große Anzahl von Ressourcen problemlos verwalten.
Fairness: Semaphore können konfiguriert werden, um sicherzustellen, dass Threads Berechtigungen auf faire Weise erhalten.
Komplexität: Die Verwendung von Semaphoren kann Ihrem Code Komplexität verleihen und das Debuggen erschweren.
Deadlocks: Bei unsachgemäßer Handhabung können Semaphoren zu Deadlocks führen, bei denen Threads auf unbestimmte Zeit blockiert werden und auf Genehmigungen warten.
Um häufige Fallstricke zu vermeiden und Semaphoren optimal zu nutzen, sollten Sie die folgenden Best Practices berücksichtigen:
Anstatt „quire()“ zu verwenden, das auf unbestimmte Zeit blockiert, können Sie „tryAcquire()“ verwenden, um zu versuchen, eine Genehmigung mit einer Zeitüberschreitung zu erhalten. Dies verhindert, dass Threads beim Warten hängen bleiben.
import java.util.concurrent.Semaphore; public class SemaphoreDemo { // Creating a semaphore with 3 permits private static final Semaphore semaphore = new Semaphore(3); public static void main(String[] args) { // Creating and starting 6 threads for (int i = 1; i <= 6; i++) { new WorkerThread("Worker " + i).start(); } } static class WorkerThread extends Thread { private String name; WorkerThread(String name) { this.name = name; } @Override public void run() { try { System.out.println(name + " is trying to acquire a permit..."); // Acquiring the semaphore semaphore.acquire(); System.out.println(name + " acquired a permit."); // Simulating work by sleeping Thread.sleep(2000); System.out.println(name + " is releasing a permit."); } catch (InterruptedException e) { e.printStackTrace(); } finally { // Releasing the semaphore semaphore.release(); } } } }
Um Ressourcenlecks zu vermeiden, geben Sie die Genehmigung immer in einem finally-Block frei. Dadurch wird sichergestellt, dass die Genehmigung auch im Ausnahmefall freigegeben wird.
Wenn Sie eine Ressource nur für einen einzelnen Thread sperren und entsperren müssen, sollten Sie die Verwendung von ReentrantLock oder synchronisiert anstelle eines binären Semaphors in Betracht ziehen.
Semaphoren sind ein leistungsstarkes Tool zur Verwaltung der Parallelität in Java, mit dem Sie die Anzahl der Threads steuern können, die auf eine gemeinsam genutzte Ressource zugreifen. Indem Sie die in diesem Artikel beschriebenen Techniken und Best Practices befolgen, können Sie Semaphoren effektiv in Ihren Java-Anwendungen implementieren, um eine sichere und effiziente Ressourcenverwaltung zu gewährleisten.
Wenn Sie Fragen haben oder Ihre eigenen Erfahrungen mit Semaphoren teilen möchten, können Sie unten gerne einen Kommentar abgeben!
Weitere Beiträge finden Sie unter: Techniken zur Verwaltung der Parallelität in Java mithilfe von Semaphoren
Das obige ist der detaillierte Inhalt vonTechniken zum Verwalten der Parallelität in Java mithilfe von Semaphoren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!