[concurrency-interest] Canceling Futures - Callable implementations

Gregg Wonderly gregg at cytetech.com
Wed Apr 8 13:59:27 EDT 2009


Peter, I just use a wrapper object in cases like this which holds the needed 
references and encompasses any actions/activities which I need to happen when 
these values change state or are used in particular ways.

This allows the specialization to be all in one place...

Gregg Wonderly

Péter Kovács wrote:
> 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
>>>
>>>
> 
> _______________________________________________
> 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