Java - use wait() method until specific time reached

10,524

Solution 1

So this question is, how can I use wait to act like sleep. If you want to use wait, you will have to use two threads. Use a ScheduledExecutorService (Tutorial).

 ScheduledExecutorService executor = newSingleThreadScheduledExecutor();

This can be done once and reused. Otherwise you have to shutdown the executor.

We'll set our deadline to be x minutes in the future, using Instant from the modern java.time framework (Tutorial).

final Instant deadline = Instant.now().plus(x, ChronoUnit.MINUTES);

Next we want to schedule a task so that our thread will wake in x minutes.

while(Instant.now().isBefore(deadline)){
    synchronized(deadline){    
        executor.schedule(
            ()->{
                synchronized(deadline){
                    deadline.notifyAll();
                }
            }, 
            Duration.between(Instant.now(),deadline).toMillis(), 
            TimeUnit.MILLISECONDS
        );
        deadline.wait();
    }
}

It is in a loop, just in case there is a spurious awake. It resubmits the task, just in case there was a spurious awake and in the meantime the other task completed and didn't wake the thread before the thread called wait again.

This above is a bit tongue in cheek. Really if you just used the following it would seem more ''realtime''.

long diff = deadline.getTimeInMillis()-now.getTimeInMillis();
if(diff>0)
    Thread.sleep(diff);

Solution 2

From oracle documentation page

public final void wait(long timeout)
                throws InterruptedException

Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.

Precondition: The current thread must own this object's monitor.

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
 }
Share:
10,524
marcuthh
Author by

marcuthh

BEng Software Engineering student and Sheffield Hallam University, currently searching for a work placement for around the time of the next academic year. C# is my specialty, although I'm proficient in other object-oriented languages such as C++ and Java. Currently working on my web design and development and have a solid level of knowledge in HTML, CSS, PHP, SQL, JavaScript and jQuery. Keen to keep learning so I do ask a lot of questions. Love the researching and testing side of things so always happy to try and solve people's problems when I get the chance. Realised I was truly a programmer the day I watched my coursemate type the word 'python' in a suggestive text to a female and it autocorrected to an uppercase 'P'. No going back once you're in with a circle like that.

Updated on June 27, 2022

Comments

  • marcuthh
    marcuthh almost 2 years

    I have a thread that runs in the background of my program and detects when a deadline (set by user input at the beginning of the program) occurs. I have implemented this in a while loop and using the sleep(1000) method.

    It all works ok, but I would like to change it over from using sleep(1000) to using wait() and notifyAll() to be consistent with the rest of my code, and to make the alert happen in real-time rather than lagging by a part of a second until the thread re-awakens.

    Here is what I currently have

        //Retrieve current date and time...
        Calendar now = Calendar.getInstance();
    
        //deadline not yet reached
        while(now.before(deadline))
        {
            try
            {
                //wait a second and try again
                sleep(1000);
            }
            catch (InterruptedException intEx)
            {
                //Do nothing.
            }
    
            //Update current date and time...
            now = Calendar.getInstance();
            //run loop again
        }
    
        ////////////////////////////
        ///alert user of deadline///
        ////////////////////////////
    

    I have tried to change it over to use wait(), but had no success. Can anybody see a way of changing the existing code over to implement the methods I mentioned?

    Thanks in advance, Mark

  • marcuthh
    marcuthh about 8 years
    Hi there, how does this method work? Will it just wait until the deadline is reached, and then drop out of the while loop?
  • Vishy
    Vishy about 8 years
    @marcuthh it does say what it does in the javadoc. Note this is for working with a lock. If you are not locking an object it doesn't make sense to wait on it.