Warten Sie, bis der boolesche Wert seinen Zustand ändert
Lesezeit: 3 Minuten
Ich habe einen Thread, der darauf wartet, dass sich ein boolescher Wert wie folgt ändert:
while(!value)
{
Thread.sleep(1000)
}
// Do some work after change of the value
Dies ist aufgrund des massiven CPU-Verbrauchs nicht meine bevorzugte Methode.
Gibt es eine Möglichkeit, den Thread zu blockieren, bis der boolesche Wert seinen Zustand ändert?
Dies ist aufgrund des massiven CPU-Verbrauchs nicht meine bevorzugte Methode.
Wenn das tatsächlich Ihr Arbeitscode ist, dann lassen Sie es einfach so. Einmal pro Sekunde einen booleschen Wert zu prüfen, verursacht KEINE messbare CPU-Last. Überhaupt keine.
Das eigentliche Problem besteht darin, dass der Thread, der den Wert überprüft, aufgrund von Caching möglicherweise eine Änderung nicht erkennt, die für eine beliebig lange Zeit aufgetreten ist. Um sicherzustellen, dass der Wert immer zwischen Threads synchronisiert wird, müssen Sie das Schlüsselwort volatile in die Variablendefinition einfügen, dh
private volatile boolean value;
Beachten Sie, dass das Einfügen des Zugriffs in a synchronized Blockieren, z. B. bei Verwendung der in anderen Antworten beschriebenen benachrichtigungsbasierten Lösung, hat den gleichen Effekt.
Marco Topolnik
Sie brauchen einen Mechanismus, der Busy Waiting vermeidet. Das alte wait/notify Mechanismus ist voller Fallstricke, also lieber etwas aus dem java.util.concurrent Bibliothek, zum Beispiel die CountDownLatch:
public final CountDownLatch latch = new CountDownLatch(1);
public void run () {
latch.await();
...
}
Und auf der anderen Seite anrufen
yourRunnableObj.latch.countDown();
Einen Thread zu starten, um nichts anderes zu tun, als zu warten, bis er benötigt wird, ist jedoch immer noch nicht der beste Weg. Sie könnten auch eine beschäftigen ExecutorService dem Sie als Aufgabe die Arbeit vorlegen, die erledigt werden muss, wenn die Bedingung erfüllt ist.
Dies hilft mir beim Testen der Quartz-Bibliothek in JUnit. Quartz führt seine Jobs in einer Blackbox aus, die über einen eigenen Thread-Pool verfügt. Ich kann JUnit signalisieren, auf den Abschluss der Quartz-Jobs zu warten, indem ich das genaue Muster verwende, das im Java-Dokument angegeben ist.
– David Mann
2. Januar 2014 um 20:16 Uhr
Kann ich die vorschlagen Java.util.concurrent.BlockingQueue und seine verschiedenen Implementierungen? Die take() und offer() Methoden sind ein guter Ausgangspunkt für die Synchronisierung.
– Groostav
6. Januar 2016 um 23:20 Uhr
Subhrajyoti Majumder
Wie wäre es mit wait-notify
private Boolean bool = true;
private final Object lock = new Object();
private Boolean getChange(){
synchronized(lock){
while (bool) {
bool.wait();
}
}
return bool;
}
public void setChange(){
synchronized(lock){
bool = false;
bool.notify();
}
}
bool ein veränderliches Feld ist, können Sie nicht darauf synchronisieren.
– axtavt
26. September 2013 um 10:21 Uhr
ähm… das ist eigentlich ein ausgezeichneter Punkt @axtavt.
– Subhrajyoti Majumder
26. September 2013 um 10:25 Uhr
Und jetzt synchronisieren Sie auf einem nicht finalen Feld. In setChange Sie ändern es zuerst und benachrichtigen dann das Neue false Beispiel. Ergebnis: Der Thread wartet auf das frühere true Instanz wird nie benachrichtigt. Noch ein gutes Beispiel dafür, warum man das tun sollte vermeiden dieser ganze Mechanismus.
– Marko Topolnik
26. September 2013 um 11:17 Uhr
ähm … danke @MarkoTopolnik. Ich denke, es ist besser, wenn ich ein explizites Sperrobjekt erstelle und damit synchronisiere. (final Object lock=new Object()), wie ist es damit?
– Subhrajyoti Majumder
26. September 2013 um 18:03 Uhr
Sie müssen auf die Sperre warten, nicht auf bool – aber die Verwendung eines einfachen CountDownLatch scheint in diesem Fall eine bessere Lösung zu sein.
– Assylias
27. September 2013 um 6:49 Uhr
Luiso1979
Ok, vielleicht sollte dieser dein Problem lösen. Beachten Sie, dass Sie jedes Mal, wenn Sie eine Änderung vornehmen, die Methode change() aufrufen, die das Warten aufhebt.
StringBuffer any = new StringBuffer();
public synchronized boolean waitTillChange() {
any.wait();
return true;
}
public synchronized void change() {
any.notify();
}
Ich bevorzuge in solchen Fällen den Mutex-Mechanismus, aber wenn Sie wirklich boolean verwenden möchten, sollten Sie ihn als flüchtig deklarieren (um die Änderung über Threads hinweg sichtbar zu machen) und einfach den körperlosen Zyklus mit diesem booleschen Wert als Bedingung ausführen:
//.....some class
volatile boolean someBoolean;
Thread someThread = new Thread() {
@Override
public void run() {
//some actions
while (!someBoolean); //wait for condition
//some actions
}
};
14413300cookie-checkWarten Sie, bis der boolesche Wert seinen Zustand ändertyes