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.

Benutzeravatar von Marko Topolnik
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

Benutzeravatar von Subhrajyoti Majumder
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

Benutzeravatar von luiso1979
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();
}

public Boolean test() throws InterruptedException {
    BlockingQueue<Boolean> booleanHolder = new LinkedBlockingQueue<>();
    new Thread(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
            booleanHolder.put(true);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
    return booleanHolder.poll(4, TimeUnit.SECONDS);
}

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 
    }

};

1441330cookie-checkWarten Sie, bis der boolesche Wert seinen Zustand ändert

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy