Question

It seems like I should be able to tell Futures apart from each other without having to maintain two HashMaps (or one bidirectional hash).

  1. Future is known when job is submitted to ExecutorService. Add Future to map with key 'jobID'.
  2. If job needs to be canceled, use 'jobID' in map to retrieve Future and cancel.
  3. If job completes successfully, Future can be identified by the returned Object (containing job ID). Remove Future from map via 'jobID'.
  4. If job is interrupted or throws an exception, no Object is returned, so the Future must be matched with the 'jobID' via calls to Future.hashCode or Future.equals (hence, two HashMaps or one bidirectional third-party hash).

Am I missing something here, or is that the expected approach? I'd like to override Future to include a 'getId' method or something, but that doesn't seem feasible based on how the executor creates them.

Edit: I'm also trying to use ExecutorCompletionService to wait for jobs to be completed.

Was it helpful?

Solution

Never use java.util.concurrent.Future. Use com.google.common.util.concurrent.ListenableFuture or similar instead. With ListenableFutures you can register callbacks when a ListenableFuture completes:

ListenableFuture<Integer> future = MoreExecutors.listeningDecorator(executor).submit(
  new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
      ...
    }
});

// Add jobId to the map. You should use a thread-safe Map!
map.put(jobId, future);

Futures.addCallback(future, new FutureCallback<Integer>(){
  @Override
  public void onSuccess(Integer result) {
    map.remove(jobId);
    ...
  }

  @Override
  public void onFailure(Throwable t) {
    map.remove(jobId);
    ...
  }});

OTHER TIPS

One way to go about this (that I have previously used) is to create a HashMap which uses a String as the key, and a Map.Entry as the value. You can easily implement the Map.Entry interface yourself, but basically it provides a tuple structure which you can use to store the Future and its associated hashCode.

The benefit of this is that it allows greater control of the fate of your Future tasks once they have started (which I think is what you're getting at?). It is a little cumbersome, though. You can handle the cases of a successful task and a manually cancelled task by simply storing an ID for the Future objects in question.

This solution really only adds the ability to handle tasks that fail to execute correctly - in which case, assuming the number of potential tasks you wish to complete is reasonable, you may be better off simply handling the exceptions as they arise and maintaining a single HashMap of previous tasks (regardless of exit status).

See the Javadoc for more on the Map.Entry interface.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top