Ich mache eine Java-Anwendung mit einem Anwendungslogik-Thread und einem Datenbankzugriffsthread. Beide bleiben während der gesamten Lebensdauer der Anwendung bestehen und müssen gleichzeitig ausgeführt werden (einer spricht mit dem Server, einer mit dem Benutzer; wenn die App vollständig gestartet ist, müssen beide funktionieren).
Beim Start muss ich jedoch sicherstellen, dass der App-Thread zunächst wartet, bis der DB-Thread bereit ist (derzeit durch Abfragen einer benutzerdefinierten Methode ermittelt dbthread.isReady()
). Es würde mir nichts ausmachen, wenn der App-Thread blockiert, bis der DB-Thread fertig ist.
Thread.join()
sieht nicht nach einer Lösung aus - der DB-Thread wird nur beim Herunterfahren der App beendet.
while (!dbthread.isReady()) {}
Art funktioniert, aber die leere Schleife verbraucht viele Prozessorzyklen.
Irgendwelche anderen Ideen? Vielen Dank.
quelle
a
auf ein Objekt wartet,synchronised(object)
wie kann dann ein anderer Thread densynchronized(object)
aufrufenobject.notifyAll()
? In meinem Programm blieb alles nur aufsynchronozed
Blöcken hängen.object.wait()
das Sperren dieses Objekts effektiv auf. Wenn der zweite Thread seinen synchronisierten Block "verlässt", werden die anderen Objekte aus derwait
Methode freigegeben und erhalten an diesem Punkt die Sperre wieder.Verwenden Sie einen CountDownLatch mit einem Zähler von 1.
Jetzt im App-Thread do-
Nachdem Sie fertig sind, tun Sie im Datenbank-Thread Folgendes:
quelle
countDown()
einenfinally{}
Block einVoraussetzung ::
Antworten ::
Job erledigt!! Siehe Beispiel unten
Ausgabe dieses Programms ::
Sie können sehen, dass es 6 Sekunden dauert, bis die Aufgabe abgeschlossen ist, die größer als bei anderen Threads ist. Future.get () wartet also, bis die Aufgabe erledigt ist.
Wenn Sie future.get () nicht verwenden, wartet es nicht auf den Abschluss und führt den basierten Zeitverbrauch aus.
Viel Glück mit Java Parallelität.
quelle
CountdownLatch
es verwendet, aber Ihr Ansatz ist weitaus flexibler.Viele richtige Antworten, aber ohne ein einfaches Beispiel. Hier ist eine einfache und einfache Verwendung
CountDownLatch
:quelle
Verwenden Sie diese Klasse dann wie folgt:
Erstellen Sie ein ThreadEvent:
In der Methode wartet dies auf Ergebnisse:
Und in der Methode, mit der die Ergebnisse erstellt werden, nachdem alle Ergebnisse erstellt wurden:
BEARBEITEN:
(Entschuldigung für die Bearbeitung dieses Beitrags, aber dieser Code hat einen sehr schlechten Rennzustand und ich habe nicht genug Ruf, um einen Kommentar abzugeben.)
Sie können dies nur verwenden, wenn Sie zu 100% sicher sind, dass signal () nach await () aufgerufen wird. Dies ist der einzige große Grund, warum Sie kein Java-Objekt wie z. B. Windows-Ereignisse verwenden können.
Wenn der Code in dieser Reihenfolge ausgeführt wird:
dann wird Thread 2 für immer warten . Dies liegt daran, dass Object.notify () nur einen der aktuell ausgeführten Threads aktiviert. Ein später wartender Thread wird nicht geweckt. Dies unterscheidet sich stark von der erwarteten Funktionsweise von Ereignissen, bei denen ein Ereignis signalisiert wird, bis a) darauf gewartet oder b) explizit zurückgesetzt wird.
Hinweis: Meistens sollten Sie notifyAll () verwenden, dies ist jedoch für das oben beschriebene Problem "Für immer warten" nicht relevant.
quelle
Probieren Sie die CountDownLatch- Klasse aus dem
java.util.concurrent
Paket aus, die Synchronisationsmechanismen auf höherer Ebene bietet, die weitaus weniger fehleranfällig sind als alle anderen Elemente auf niedriger Ebene.quelle
Sie können dies mit einem Exchanger- Objekt tun, das von den beiden Threads gemeinsam genutzt wird:
Und im zweiten Thread:
Wie andere gesagt haben, nehmen Sie diesen unbeschwerten Code nicht und kopieren Sie ihn einfach. Lesen Sie zuerst etwas.
quelle
Die Future- Schnittstelle aus dem
java.lang.concurrent
Paket bietet Zugriff auf Ergebnisse, die in einem anderen Thread berechnet wurden.Werfen Sie einen Blick auf FutureTask und ExecutorService, um eine vorgefertigte Methode zu finden.
Ich würde jedem, der sich für Parallelität und Multithreading interessiert, dringend empfehlen, Java Concurrency In Practice zu lesen . Es konzentriert sich offensichtlich auf Java, aber es gibt viel Fleisch für jeden, der auch in anderen Sprachen arbeitet.
quelle
Wenn Sie etwas schnelles und schmutziges wollen, können Sie einfach einen Thread.sleep () -Aufruf in Ihre while-Schleife einfügen. Wenn Sie die Datenbankbibliothek nicht ändern können, gibt es wirklich keine andere einfache Lösung. Wenn Sie die Datenbank abfragen, bis eine Wartezeit erreicht ist, wird die Leistung nicht beeinträchtigt.
Kaum etwas, das man als eleganten Code bezeichnen könnte, aber die Arbeit erledigt.
Wenn Sie den Datenbankcode ändern können, ist es besser, einen Mutex zu verwenden, wie in anderen Antworten vorgeschlagen.
quelle
Dies gilt für alle Sprachen:
Sie möchten ein Ereignis- / Listener-Modell haben. Sie erstellen einen Listener, der auf ein bestimmtes Ereignis wartet. Das Ereignis wird in Ihrem Worker-Thread erstellt (oder signalisiert). Dadurch wird der Thread blockiert, bis das Signal empfangen wird, anstatt ständig abzufragen, ob eine Bedingung erfüllt ist, wie die derzeitige Lösung.
Ihre Situation ist eine der häufigsten Ursachen für Deadlocks. Stellen Sie sicher, dass Sie den anderen Thread unabhängig von möglicherweise aufgetretenen Fehlern signalisieren. Beispiel: Wenn Ihre Anwendung eine Ausnahme auslöst und niemals die Methode aufruft, um dem anderen zu signalisieren, dass die Dinge abgeschlossen sind. Dadurch wird der andere Thread niemals "aufwachen".
Ich schlage vor, dass Sie sich mit den Konzepten der Verwendung von Ereignissen und Ereignishandlern befassen, um dieses Paradigma besser zu verstehen, bevor Sie Ihren Fall implementieren.
Alternativ können Sie einen blockierenden Funktionsaufruf mit einem Mutex verwenden, wodurch der Thread darauf wartet, dass die Ressource frei ist. Dazu benötigen Sie eine gute Thread-Synchronisation, z. B.:
quelle
Sie können in einem Thread aus einer blockierenden Warteschlange lesen und in einem anderen Thread darauf schreiben.
quelle
Schon seit
join()
wurde ausgeschlossenSie können andere Alternativen in Betracht ziehen:
invokeAll from
ExecutorService
ForkJoinPool oder newWorkStealingPool von
Executors
(seit Java 8 Release)quelle
Diese Idee kann zutreffen?. Wenn Sie CountdownLatches oder Semaphoren verwenden, funktioniert dies perfekt, aber wenn Sie nach der einfachsten Antwort für ein Interview suchen, kann dies meiner Meinung nach zutreffen.
quelle