Java - Priorität im Semaphor

8

Ich habe mehrere Threads, die auf eine externe Ressource zugreifen - einen Browser. Aber nur ein Thread kann gleichzeitig darauf zugreifen. Also benutze ich einen Semaphor, um sie zu synchronisieren. Jedoch sollte ein Thread, der Eingaben von der GUI erhält und dann auf den Browser für die Ergebnisse zugreift, Vorrang vor anderen Threads haben, und ich bin nicht sicher, wie ein Semaphor dazu verwendet werden kann.

Ich dachte, dass jeder Thread nach dem Erfassen des Semaphors prüft, ob der Prioritätsfaden in der Warteschlange wartet, und wenn ja, dann gibt er ihn frei und wartet erneut. Nur der Prioritäts-Thread gibt es nicht frei, sobald es erfasst wurde.

Ist das eine gute Lösung oder gibt es noch etwas in Java API, das ich verwenden könnte?

    
Ľubomír 11.09.2016, 15:01
quelle

3 Antworten

2

Hier ist eine einfache Antwort ohne Schnickschnack. Dies ist ähnlich wie eine Lese- / Schreibsperre funktioniert, außer dass jedes Schließfach exklusiven Zugriff hat (normalerweise laufen alle Leser parallel). Beachten Sie, dass nicht Semaphore verwendet, da dies fast immer das falsche zu verwendende Konstrukt ist.

%Vor%

Sie würden es wie einen der Lock-Typen in java.util.concurrent verwenden:

Normale Threads:

%Vor%

"Priorität" -Thread:

%Vor%

UPDATE:

Antwort auf einen Kommentar zu "präemptiven" Thread-Interaktionen:

Im Allgemeinen können Sie das nicht tun. Sie könnten benutzerdefinierte Funktionen erstellen, die dem gesperrten Abschnitt "Pause-Punkte" hinzufügen, die es einem Thread mit niedriger Priorität ermöglichen, einem Thread mit hoher Priorität zu folgen, aber das wäre voller Gefahren.

Das einzige, was Sie realistisch tun könnten, ist das Unterbrechen des Arbeits-Threads , der dazu führt, dass er den gesperrten Codeblock verlässt (vorausgesetzt, dass Ihr Arbeitscode auf Unterbrechung reagiert hat). Dies würde es einem Thread mit hoher Priorität ermöglichen, schneller auf Kosten der Thread-Verarbeitung mit niedriger Priorität, die gerade ausgeführt wird, voranzukommen (und Sie müssen möglicherweise auch eine Rollback-Logik implementieren).

Um dies zu implementieren, müssten Sie:

  1. Zeichnen Sie den "aktuellen Thread" auf, wenn das Sperren erfolgreich ist.
  2. in lockPriority() , unterbricht den "aktuellen Thread" falls gefunden
  3. implementiert die Logik zwischen den Aufrufen lock() / unlock() (niedrige Priorität), so dass:
    1. es reagiert auf Unterbrechung in einem vernünftigen Zeitrahmen
    2. es implementiert jeden erforderlichen "Rollback" -Code, wenn er unterbrochen wird
  4. implementiert möglicherweise "retry" Logik außerhalb die lock() / unlock() (niedrige Priorität) Aufrufe, um jede verlorene Arbeit wiederherzustellen, wenn unterbrochen
jtahlborn 11.09.2016, 19:55
quelle
6

In Java gibt es keine Synchronisationsprimitive, mit denen Sie einen Thread gegenüber anderen auf die von Ihnen gewünschte Weise priorisieren könnten.

Aber Sie könnten einen anderen Ansatz zur Lösung Ihres Problems verwenden. Anstatt Threads zu synchronisieren, sollten Sie sie dazu bringen, kleine Tasks zu erzeugen (zB Runnable objects) und diese Tasks in ein PriorityBlockingQueue mit Tasks aus dem GUI-Thread mit der höchsten Priorität zu setzen. Ein einzelner Arbeits-Thread wird Aufgaben aus dieser Warteschlange abfragen und ausführen. Das würde sowohl den gegenseitigen Ausschluss als auch die Priorisierung garantieren.

In ThreadPoolExecutor gibt es spezielle Konstruktoren, die blockierende Warteschlangen akzeptieren. Alles, was Sie brauchen, ist ein solcher Executor mit einem einzelnen Thread, der mit Ihrem PriorityBlockingQueue<Runnable> bereitgestellt wird. Übergeben Sie dann Ihre Aufgaben an diesen Executor und es wird sich um den Rest kümmern.

Sollten Sie sich für diesen Ansatz entscheiden, könnte dieser Beitrag für Sie von Interesse sein: So implementieren Sie PriorityBlockingQueue mit ThreadPoolExecutor und benutzerdefinierten Aufgaben

    
Andrew Lygin 11.09.2016 17:32
quelle
0

Sie vermischen Konzepte hier.

Semaphore sind nur eine der vielen Optionen, um die Interaktionen von Threads zu "synchronisieren". Sie haben nichts mit Thread-Prioritäten und der Thread-Planung zu tun.

Thread-Prioritäten sind dagegen ein eigenständiges Thema. Sie haben Mittel in Java, um sie zu beeinflussen; Die Ergebnisse solcher Aktionen hängen jedoch stark von der zugrunde liegenden Plattform / dem zugrunde liegenden Betriebssystem ab. und die JVM-Implementierung selbst. In der Theorie ist die Verwendung dieser Prioritäten einfach , aber wie gesagt; Die Realität ist mehr kompliziert .

Mit anderen Worten: Sie können Ihren Semaphor nur verwenden, um sicherzustellen, dass nur ein Thread Ihre Warteschlange zu einem bestimmten Zeitpunkt verwendet. Es hilft überhaupt nicht sicherzustellen, dass Ihr GUI-Lese-Thread gegenüber anderen Threads Vorrang hat, wenn CPU-Zyklen zu einem Problem werden. Aber wenn Sie Glück haben, wird die Antwort auf Ihr Problem einfache Aufrufe an setPriority () ; verschiedene Prioritäten verwenden.

    
GhostCat 11.09.2016 15:21
quelle

Tags und Links