[concurrency-interest] Canceling Futures - Callable implementations

Péter Kovács peter.kovacs.1.0rc at gmail.com
Wed Apr 8 13:10:53 EDT 2009


One application of this approach where I cannot find an elegant
solution is when I want to use an ExecutorCompletionService for
"joining" a definite number of "cancelable" concurrent tasks:

With a hypothetical collaboration of future-aware Callables, Futures
and Executors built into the API, I could (1) store the futures
returned by ExecutorCompletionService.submit in a list, (2) remove
from the list each future returned by ExecutorCompletionService.take,
(3) get the result off of the same future and (4) check if the list is
empty to see if more futures need to be taken from the ECS. Something
like:

while (myFutures.size() > 0) {
    Future<String> f = executorCompletionService.take();
    myFutures.remove(f);
    f.get();
}

Using the "MyTask approach" with ECS, I have to do something like this:

while (nrCompletedTasks < myTasks.size()) {
    Future<String> f = executorCompletionService.take();
    nrCompletedTasks++;
    f.get();
}

Here, I have the extra job of keeping track of the number of finished
tasks -- in addition to storing references to the tasks (MyTasks) for
potential canceling. Also -- as it is unknown which MyTask instance
corresponds to a given future returned by ECS.take() --, I end up
using MyTask only for cancellation and the ECS-generated futures for
getting the results. As Future is basically meant to be a "handle" to
an asynchronous task, having to unrelated "handle" to the same task
with split functionality is (conceptually) confusing.

Comments appreciated.

Thanks
Peter

2009/4/8 Péter Kovács <peter.kovacs.1.0rc at gmail.com>:
> Joe,
>
> Thank you for your clarification.
>
> Looking more closely at your sample code and at the API, I've come to
> the conclusion that this approach will do a fairly decent job in my
> case as well.
>
> Thanks again
> Peter
>
> On Tue, Apr 7, 2009 at 11:34 PM, Joe Bowbeer <joe.bowbeer at gmail.com> wrote:
>> Peter,
>>
>> My uses of ExecutorService tend to be centered around Future/Runnable tasks
>> rather than Callables, and I've always felt that the avenue for extension in
>> this area is through task customization.  Callable is supported as a
>> convenience, but it's not convenient in every situation...
>>
>> What prevents you from executing your own tasks (e.g., MyTask)?  Or rather,
>> why do you think it's important to support a new flavor of Callable instead?
>>
>> Joe
>>
>> 2009/4/7 Péter Kovács
>>>
>>> Joe,
>>>
>>> Thank you for your reply.
>>>
>>> I like your suggestion for a 'better "Callable"'. Couldn't it be
>>> included in the API with the ExecutorService et al. supporting it?
>>> Implementing against it would be, in a number of cases, much more
>>> straightforward than with the current apparatus.
>>>
>>> Thanks
>>> Peter
>>>
>>> On Tue, Apr 7, 2009 at 7:10 PM, Joe Bowbeer wrote:
>>> > Peter,
>>> >
>>> > Callable was designed to be useful stand-alone, like Runnable.  Because
>>> > of
>>> > this, Callable has no more knowledge of its Future (if associated) than
>>> > Runnable has of its Thread, and therein lies the rub when one is trying
>>> > to
>>> > write a Callable that knows the state of its Future.
>>> >
>>> > A better "Callable" for the purpose of detecting cancellation might have
>>> > been:
>>> >
>>> >   public interface MyCallable<V> {
>>> >       V call(Future task) throws Exception;
>>> >   }
>>> >
>>> > Then you could write "callables" of the form:
>>> >
>>> >   MyCallable<Integer> mc = new MyCallable<Integer>() {
>>> >       public Integer call(Future task) {
>>> >           while (!task.isCancelled()) {
>>> >               Thread.yield(); // Please!!
>>> >           }
>>> >           return 0;
>>> >       }
>>> >   };
>>> >
>>> > Below is a Task class that uses these instead:
>>> >
>>> > class MyTask<V> implements Future<V>, Runnable {
>>> >
>>> >     protected final FutureTask<V> task;
>>> >
>>> >     public MyTask(final MyCallable<V> mc) {
>>> >         task = new FutureTask<V>(new Callable<V>() {
>>> >             public V call() throws Exception {
>>> >                 return mc.call(task);
>>> >             }
>>> >         });
>>> >     }
>>> >
>>> >     /* Runnable implementation. */
>>> >
>>> >     public void run() {
>>> >         task.run();
>>> >     }
>>> >
>>> >     /* Future implementation. */
>>> >
>>> >     public boolean cancel(boolean mayInterruptIfRunning) {
>>> >         return task.cancel(mayInterruptIfRunning);
>>> >     }
>>> >
>>> >     public boolean isCancelled() {
>>> >         return task.isCancelled();
>>> >     }
>>> >
>>> >     public boolean isDone() {
>>> >         return task.isDone();
>>> >     }
>>> >
>>> >     public V get() throws InterruptedException, ExecutionException {
>>> >         return task.get();
>>> >     }
>>> >
>>> >     public V get(long timeout, TimeUnit unit)
>>> >         throws InterruptedException, ExecutionException,
>>> > TimeoutException {
>>> >         return task.get(timeout, unit);
>>> >     }
>>> > }
>>> >
>>> > This internal FutureTask construction is also found in SwingWorker, by
>>> > the
>>> > way.
>>> >
>>> > Joe
>>> >
>>> > 2009/4/7 Péter Kovács
>>> >>
>>> >> Hi,
>>> >>
>>> >> How will a Callable implementation know that the corresponding Future
>>> >> has been canceled?
>>> >>
>>> >> One mechanism I am aware of is thread interruption, but practice shows
>>> >> that relying on this mechanism is highly unsafe. For interruption
>>> >> checks to work safely, everyone up the call stack would have to
>>> >> observe the related protocol, which is rarely the case.
>>> >>
>>> >> Is there anything else in place for this purpose? If there is not,
>>> >> wouldn't it be reasonable to provide a "useful" default implementation
>>> >> of Callable -- along the lines of FutureTask being an implementation
>>> >> of Future?
>>> >>
>>> >> Thanks
>>> >> Peter
>>> >
>>
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>>
>



More information about the Concurrency-interest mailing list