maidh91 / guava-libraries

Automatically exported from code.google.com/p/guava-libraries
Apache License 2.0
0 stars 0 forks source link

A Future that always times out #486

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Guava provides Futures that populate a value/exception immediately, but I've 
got a use-case for a Future that populates a value/exception after some 
predetermined time.

I'd like to implement the Null Object design pattern for a 
AsynchronousByteChannel associated with a disconnected device. All I/O 
operations are expected to time out because no data will ever be read or 
written. Some methods return a Future, so I need to implement a Future that 
always times out waiting for a value. Extrapolating this to a more general 
case, I propose implementing a Future where the value is populated after some 
pre-determined time. That is:

Futures.newFutureValue(V value, long timeout, TimeUnit unit);
Futures.newFutureException(Throwable throwable, long timeout, TimeUnit unit);
Futures.newCheckedFutureValue(V value, long timeout, TimeUnit unit);
Futures.newCheckedFutureException(E exception, long timeout, TimeUnit unit);

Original issue reported on code.google.com by cowwoc...@gmail.com on 23 Nov 2010 at 9:32

GoogleCodeExporter commented 9 years ago
Here is a sample implementation using joda-time (easily replaced):

/**
 * A future with a predetermined execution path.
 *
 * @param <V> the return type of the Future
 */
public class PredeterminedFuture<V> implements Future<V>
{
    private boolean cancelled;
    private boolean done;
    private final V value;
    private final Throwable throwable;
    private final DateTime publishTime;

    /**
     * Creates a new PredeterminedFuture.
     *
     * If <code>throwable</code> is non-null, the Future will throw the exception; otherwise,
     * it return the value.
     *
     * @param value the value to return
     * @param throwable the Throwable to throw
     * @param timeout the amount of time to wait before publishing the result
     * @param unit the unit of timeout
     */
    public PredeterminedFuture(V value, Throwable throwable, long timeout, TimeUnit unit)
    {
        this.value = value;
        this.throwable = throwable;
        if (timeout == Long.MAX_VALUE)
        {
            // never publish the result
            this.publishTime = null;
        }
        else
            this.publishTime = new DateTime(unit.toMillis(timeout));
    }

    @Override
    public synchronized boolean cancel(boolean mayInterruptIfRunning)
    {
        if (publishTime == null || publishTime.isAfterNow())
        {
            cancelled = true;
            done = true;
            notifyAll();
        }
        return cancelled;
    }

    @Override
    public synchronized boolean isCancelled()
    {
        return cancelled;
    }

    @Override
    public synchronized boolean isDone()
    {
        return done;
    }

    /**
     * Waits until the Future is done or times out.
     *
     * @param wakeupTime indicates when to return even if <code>done</code> is false, null of
     * the method should wait for <code>done</code>
     * @throws InterruptedException if the thread is interrupted
     */
    private synchronized void waitUntil(DateTime wakeupTime) throws InterruptedException
    {
        while (!done)
        {
            long timeLeft;
            if (wakeupTime == null)
                timeLeft = Long.MAX_VALUE;
            else
            {
                DateTime now = new DateTime();
                timeLeft = new Duration(now, wakeupTime).getMillis();
            }
            if (timeLeft <= 0)
            {
                done = true;
                break;
            }
            TimeUnit.MILLISECONDS.timedWait(this, timeLeft);
        }
    }

    @Override
    public synchronized V get() throws InterruptedException, ExecutionException
    {
        waitUntil(publishTime);
        if (cancelled)
            throw new CancellationException();
        if (throwable != null)
            throw new ExecutionException(throwable);
        return value;
    }

    @Override
    public synchronized V get(long timeout, TimeUnit unit) throws InterruptedException,
                                                                                                                                ExecutionException, TimeoutException
    {
        DateTime startTime = new DateTime();
        DateTime earliestEvent = startTime.plus(unit.toMillis(timeout));
        if (publishTime != null && publishTime.isBefore(earliestEvent))
            earliestEvent = publishTime;
        waitUntil(earliestEvent);
        if (cancelled)
            throw new CancellationException();
        if (throwable != null)
            throw new ExecutionException(throwable);
        return value;
    }
}

Original comment by cowwoc...@gmail.com on 23 Nov 2010 at 10:38

GoogleCodeExporter commented 9 years ago
Updated source-code. Future.get(long, TimeUnit) was never throwing 
TimeoutException.

Original comment by cowwoc...@gmail.com on 24 Nov 2010 at 2:46

Attachments:

GoogleCodeExporter commented 9 years ago
I'm a little confused; is your need for a Future that always times out, or one 
that populates after a set period of time?  This report seems to mix the two.

These things seem like they would have pretty limited use outside of testing 
(and possibly dangerous in testing, when those timeouts invariably lead to 
flaky tests).

Original comment by kevinb@google.com on 12 Jan 2011 at 10:44

GoogleCodeExporter commented 9 years ago

Original comment by kevinb@google.com on 12 Jan 2011 at 11:12

GoogleCodeExporter commented 9 years ago
In retrospect, my specific case (implementing the Null Object Pattern for a 
disconnected device) needed a Future that always times out (not one that 
populates with a value/exception after a certain amount of time). This object 
was used at runtime, not in test code.

Original comment by cowwoc...@gmail.com on 12 Jan 2011 at 11:17

GoogleCodeExporter commented 9 years ago
Would be very good to hear if anyone else needs this.

Original comment by kevinb@google.com on 26 Jan 2011 at 2:24

GoogleCodeExporter commented 9 years ago
A future that blocks forever on get() (until interrupted) sounds like fun, if 
only for testing.
But it can easily be done with SettableFuture?

Original comment by earwin@gmail.com on 5 Jun 2011 at 1:44

GoogleCodeExporter commented 9 years ago

Original comment by kevinb@google.com on 13 Jul 2011 at 6:18

GoogleCodeExporter commented 9 years ago
That's true, earwin.

Original comment by kevinb@google.com on 1 Aug 2011 at 9:24

GoogleCodeExporter commented 9 years ago
This issue has been migrated to GitHub.

It can be found at https://github.com/google/guava/issues/<id>

Original comment by cgdecker@google.com on 1 Nov 2014 at 4:15

GoogleCodeExporter commented 9 years ago

Original comment by cgdecker@google.com on 3 Nov 2014 at 9:09