views:

176

answers:

3

I'm trying to implement Future.get(long, TimeUnit) in terms of TimeUnit.timedWait(Object, long).

It's not clear how to use TimeUnit.timedWait(Object, long) in a way that handles spurious wakeups without losing the nanosecond component of TimeUnit. Normally you'd do something like this:

public V get(long timeout, TimeUnit unit)
{
  long expirationTime = new Date().getTime() + unit.toMillis(timeout);
  while (!condition)
  {
    long timeLeft = expirationTime - new Date().getTime();
    if (timeLeft <= 0)
      throw new TimeoutException();
    unit.timedWait(object, timeLeft);
  }
}

but you lose the nanosecond component. If everyone is simply dropping the nanosecond component then what is the point of TimeUnit even supporting nanoseconds and offering TimeUnit.timedWait()?

+3  A: 

Before you wait, store the time at which you want to timeout.

Before you notify the waiting thread, set some shared (synchronized) state signalling that the waiting thread should stop waiting because the computation is complete.

When your thread wakes up from the wait for whatever reason it should check the shared state to see if it should stop waiting, and it should also check how long is left before the timeout expires. If the timeout has not expired, and the shared state tells does not say to stop waiting then you should wait again (but using a new shorter time out calculated from the current time).

Mark Byers
It's not clear how to store the time at which you want to timeout without losing the nanosecond component of TimeUnit. If everyone is simply dropping the nanosecond component then what is the point of TimeUnit even supporting nanoseconds and offering TimeUnit.timedWait()?
Gili
Wow, good point Gili. Deep, but good point.
LWoodyiii
Well I can't really say why they chose to allow nanosecond precision. In practice I doubt you will get that precision anyway from an ordinary operating system. And if you do need that precision then using a garbage collected language sounds like a really bad idea.
Mark Byers
I've updated the question to be more TimeUnit-centric but I've given you an up-vote for the great Object.wait() advise.
Gili
+1  A: 

The answer to your question lies in the Object.wait(long) spec:

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).

LWoodyiii
You need to remember to decrease the timeout the second time you wait as some of the time has already passed.
Mark Byers
A: 

CountDownLatch seems to be the easiest way to implement this:

public class MutableFuture<T> implements Future<T>
{
  private final CountDownLatch done = new CountDownLatch(1);
  private T value;
  private Throwable throwable;

  public synchronized boolean isDone()
  {
    return done.getCount() == 0;
  }

  public synchronized T get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException
  {
    if (!done.await(timeout, unit))
      throw new TimeoutException();
    if (throwable != null)
      throw new ExecutionException(throwable);
    return value;
  }

  // remaining methods left as exercise to the reader :)
}
Gili