58

I have a thread which wait for a boolean value to change like this:

while(!value)
{
  Thread.sleep(1000)
}
// Do some work after change of the value

This is not my prefered way to do this, cause of massive CPU consumption.

Is there any way to block the Thread, until the boolean value changes it state?

marc3l
  • 2,525
  • 7
  • 34
  • 62

6 Answers6

95

This is not my prefered way to do this, cause of massive CPU consumption.

If that is actually your working code, then just keep it like that. Checking a boolean once a second causes NO measurable CPU load. None whatsoever.

The real problem is that the thread that checks the value may not see a change that has happened for an arbitrarily long time due to caching. To ensure that the value is always synchronized between threads, you need to put the volatile keyword in the variable definition, i.e.

private volatile boolean value;

Note that putting the access in a synchronized block, such as when using the notification-based solution described in other answers, will have the same effect.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
66

You need a mechanism which avoids busy-waiting. The old wait/notify mechanism is fraught with pitfalls so prefer something from the java.util.concurrent library, for example the CountDownLatch:

public final CountDownLatch latch = new CountDownLatch(1);

public void run () {
  latch.await();
  ...
}

And at the other side call

yourRunnableObj.latch.countDown();

However, starting a thread to do nothing but wait until it is needed is still not the best way to go. You could also employ an ExecutorService to which you submit as a task the work which must be done when the condition is met.

t0r0X
  • 4,212
  • 1
  • 38
  • 34
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • This helps me for testing the Quartz library inside of JUnit. Quartz runs its jobs in a blackbox that has its own thread pool. I can signal JUnit to wait for the quartz jobs to complete using the exact pattern specified in the java doc. – David Mann Jan 02 '14 at 20:16
  • 3
    Can I suggest the `Java.util.concurrent.BlockingQueue` and its various implementations? The `take()` and `offer()` methods are a great starting place for synchronization. – Groostav Jan 06 '16 at 23:20
6

How about 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();
   }
}
Subhrajyoti Majumder
  • 40,646
  • 13
  • 77
  • 103
  • 15
    `bool` is a mutable field, you cannot synchronize on it. – axtavt Sep 26 '13 at 10:21
  • umm... that is actually a execelent Point @axtavt. – Subhrajyoti Majumder Sep 26 '13 at 10:25
  • 2
    And now you are synchronizing on a non-final field. In `setChange` you'll first modify it and then notify the new `false` instance. Result: the thread waiting on the earlier `true` instance never gets notified. Yet another fine example of why to *avoid* this entire mechanism. – Marko Topolnik Sep 26 '13 at 11:17
  • ummm... thanks @MarkoTopolnik I think it'll be better if I create explicit lock object and synchronized using that.(`final Object lock=new Object()`), how about that? – Subhrajyoti Majumder Sep 26 '13 at 18:03
  • Yes, that would be best. Also make sure you both synchronize on it and wait/notify on it. – Marko Topolnik Sep 26 '13 at 18:07
  • You wait/notify on the wrong object - and there is little reason to use wait/notify for that use case IMO... – assylias Sep 26 '13 at 21:48
  • @assylias what would you suggest me to do? – Subhrajyoti Majumder Sep 27 '13 at 06:41
  • 4
    You need to wait on lock, not bool - but using a simple CountDownLatch seems a better solution in this case. – assylias Sep 27 '13 at 06:49
  • `Is there any way to block the Thread, until the boolean value changes it state?` it was the question. `CountDownLatch ` I believe so, its really better. – Subhrajyoti Majumder Sep 27 '13 at 07:01
  • `bool.wait` theoretically throws an uncatched `InterruptedException`. And calling `bool.wait` causes an `IllegalMonitorStateException` because you are not synchronized on `bool` but `lock` - can you show how that code is *supposed* to be used? – luk2302 Jan 16 '17 at 08:29
  • could someone please delete this not working solution? – Zordid Aug 17 '22 at 14:06
1

Ok maybe this one should solve your problem. Note that each time you make a change you call the change() method that releases the wait.

StringBuffer any = new StringBuffer();

public synchronized boolean waitTillChange() {
    any.wait();
    return true;
}

public synchronized void change() {
    any.notify();
}
luiso1979
  • 868
  • 1
  • 6
  • 18
0
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);
}
k4dima
  • 6,070
  • 5
  • 41
  • 39
-1

I prefer to use mutex mechanism in such cases, but if you really want to use boolean, then you should declare it as volatile (to provide the change visibility across threads) and just run the body-less cycle with that boolean as a condition :

//.....some class

volatile boolean someBoolean; 

Thread someThread = new Thread() {

    @Override 
    public void run() {
        //some actions
        while (!someBoolean); //wait for condition 
        //some actions 
    }

};