[concurrency-interest] differentiating between result-bearing and non- result-bearing actions

Tim Peierls tim@peierls.net
Sat, 17 Jan 2004 00:20:25 -0500


Gary Moyer wrote:
> Thus Future.get() returns null when the instance is returned by any of the
> following ScheduledExecutorService methods:
> 
> 1: schedule(Runnable command, long delay, TimeUnit unit)
> 2: scheduleAtFixedRate(Runnable command, ...)
> 3: scheduleWithFixedDelay(Runnable command, ...)
> 
> What's confusing is null may likewise represent a "usable" result.  ...
> I would ask that if Future is going to be used in this capacity then it should
> also provide a method to indicate the usable-ness of the result.

Not sure I understand how you could lose track of which futures are
ScheduledFuture<?> (for which the return value of get() is irrelevant),
but if this somehow did arise in practice, you could wrap your Runnables
up front as Callable<U>, where U is only used to denote unusable values.
If you use this approach, any null returns from get() will be legitimate
null values.

     private enum Unusable { VALUE }

     public static boolean usableValue(Object o) {
         return o != Unusable.VALUE;
     }

     public static ScheduledFuture<?> schedule(
             ScheduledExecutorService service, Runnable task,
             long delay, TimeUnit unit) {

         return service.schedule(Executors.callable(task, Unusable.VALUE),
                                 delay, unit);
     }

But it would be much better to keep track of Future<?> returns from
schedule(Runnable,...) separately from Future<T> returns from
schedule(Callable<T>,...). Then you won't be tempted to interpret
the result of calling get() on a Future<?>.

--tim