views:

250

answers:

2

Let's say I do something in Java like:


RemoteResponse response = null;
try {
   FutureTask task new FutureTask(....);
   executor.execute(task);
   response = task.get(1000, TimeUnits.MILLISECONDS);
}
catch( TimeoutException te ) {
   
   .. should I do something special here? ...
   .. what happens to the return value of the task if task.get() throws an exception? ...
   .. is it ever garbage collected? ..
   
}

My question is does something hold onto RemoteResponse in the case where TimeoutException is thrown? Will it get garbage collected? Do I have to call the cancel() method on the task for that to happen?

+3  A: 

Edit after the question was revised:

response is a reference to a RemoteResponse that task is responsible for allocating. The assignment of the return value from a method won't happen if the method threw an exception, so there is no need for special handling of response.

task will be unreferenced when it goes out of scope, either through normal execution or if an exception is thrown.

If the resources allocated by task are well encapsulated, ie there are no externally held references, and are released (close, release, whatever), then there should be no resource leakage.

There's no need to call cancel unless there is some shared resource the task has exclusively or some other consumable resource that the rest of the application needs.

I'd at least log the fact that the task didn't complete in the time allotted. What else you do depends on the requirements of your application.

Note that task will continue executing until completion, regardless of the get call.

Ken Gentle
A: 

I think the way to look at the problem is that you need to claim the resource outside of the FutureTask, so that when you do decide to cancel it you can force the reclamation of resources.

so:

Resource res = null;
try {
 resource = ResourceAquirer.claim()

 FutureTask<?> task = new FutureTask<?>(resource);
 executor.execute(task);   
 response = task.get(1000, TimeUnits.MILLISECONDS);
} catch (Exception e) {
  // logging
} finally {
 if (resource != null) {
   resource.release();
 }
}

This way you can be sure that the resource will be freed. It is really frustrating that all of that cannot be encapuslated inside the future task, but I cannot find proof that calling cancel on a futuretask will ensure that a finally block is invoked inside the FutureTask. (Maybe I'll ask that as another question)

Nathan Feger
That looks like a good approach.
Dave
If one calls Future#cancel() on a FutureTask and that call actually cancels the operation -- assuming it hasn't been previously canceled or already finished running -- the protected method FutureTask#done() will be called. Within done(), you can call Future#isCancelled() to see if you finished by virtue of cancellation. In other words, done() will only be called at most once. If you never call run() or cancel() on the FutureTask, done() will never be called.
seh