简体   繁体   中英

Java: Wait a boolean to become true

I implemented a task which current thread will wait until previous work is done.

Code:

    while (!taskContext.isPreviousWorkDone()) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            LOGGER.error("Wait failed", e);
        }
    }
    doSomething();

Another thread will set isPreviousWorkDone to true and then we can run doSomething() . But I think my code is bad:

  1. we check that every 100ms , and it may cost some CPU resource.
  2. It's hard to add a wait timeout. (What if isPreviousWorkDone never become true?)

So, how to implement such a wait properly?

Use a CountDownLatch instead. A java.util.concurrent.CountDownLatch allows one or more threads to wait for some operation(s) to complete.

A CountDownLatch is initialized with a given count. Threads that need to wait for some condition/operation (for the count to reach zero), call one of the await() methods. The count is decremented from the thread that completed some operation by invoking the countdown() method. Then, all waiting threads continue execution.

Example

// create latch with count of one (1)
CountDownLatch latch = new CountDownLatch(1);

// create instances of classes that implement Runnable
Waiter waiter = new Waiter(latch);
Worker worker = new Worker(latch);

// start threads
new Thread(waiter).start();
new Thread(worker).start();

Define Waiter Runnable (waits for some operation to complete)

public class Waiter implements Runnable{
    CountDownLatch latch = null;

    public Waiter(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {
        try {
            // wait for the latch to be released
            latch.await();
        } catch (InterruptedException e) {
            // set interupt flag
            Thread.currentThread().interrupt();
            // log interrupt
            System.out.println("Interrupted");
        }
        System.out.println("Unblocked");

        doSomething();
    }
}

Define Worker Runnable (executes some operation)

public class Worker implements Runnable {
    CountDownLatch latch = null;

    public Worker(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {
        // do some job

        // when ready release latch
        latch.countDown();

        System.out.println("Latch Released");
    }
}

Avoid

Using the old wait-notify java API. The reason is the spurious wakeups . That is your thread wakes up without being actually notified, so you have to check that your condition is satisfied or else keep waiting.

Spurious wakeups from javadocs

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }

(For more information on this topic, see Section 3.2.3 in Doug Lea's "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, 2000), or Item 50 in Joshua Bloch's "Effective Java Programming Language Guide" (Addison-Wesley, 2001).

What you are trying to achieve is a work for monitors. Using an object acting as a monitor, you can make threads wait/awake whenever you need to.

synchronized(lock)
{
    while(!taskContext.isPreviousWorkDone())
    {
        try
        {
            // Object lock has to be accessible both by waiting thread and any
            // other thread that marks the previous work as done
            lock.wait();
        }   
    }
}

Now, wherever you update task context, you must awake the awaiting threads

// Method where you update taskContext
public synchronized void setWorkAsDone() throws Exception
{
    // ...
    _isPreviousWorkDone = true;
    notifyAll();
    // ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM