views:

56

answers:

3

I am still learning about using Future and Callable in Java. Stumble into this question:

Say I have class:

TaskWorker implements Callable {
  public String id;
  public TaskWorker(String id) {
     this.id = id;
  }

  public Documents call() trows Exception {
       //Assume here, that Search and Doc are my own method to search and retrieve docs
       Search search =  new Search();
       Documents docResult = search.process(id);

       //think about documents has getDocs
       //docResult.getDocs() will return number of document found from search

       return docResult;
  }
}

And here is the main method:

public static void main(String[] args) {
   //assume here, that I build in request contains many Id

   Request request = new Request();
   request.process;

   ExecutorService service = Executors.newFixedThreadPool(3);
   List<Future<Documents>> result = new ArrayList<Future<Documents>>();

   for (int i=0;i<request.length;i++) {
       Callable<Documents> worker = new TaskWorker(request.getId[i]);
       Future<Documents> submit = executor.submit(worker);
       result.add(submit);
   }

   Response response = new Response();
   ArrayList<Documents> docList = new ArrayList<Documents>();

   for (Future<Documents> future:result) {
     docList.add(future.get().getDocs());
   }

   response.setDocuments(docList);
}

What I am trying to do is, breaking a part the request to run in separate thread since each of the request Id is separate Search process. So I am trying to utilize Java pooling, by storing the result in the future object.

The thing I am confused is, how does future will work in this case? For each thread completion, is it going to hold the results? And after all the process finish, I can just loop future object to get the results right?

Also, there is no guarantee that process will run in order (1,2,3,4,etc), right? If that the case, then what is the best strategy if I want to associate each original request with the future result?

Please advise.

Thanks

A: 

You should create SynchronizedMap and pass it to TaskWorker in constructor together with a Request. TaskWorker should add Request and Result to the map when it finishes the job.

You dont have to loop Futures to get results, just make sure all jobs are finished.

Peter Knego
A: 

The thing I am confused is, how does future will work in this case? For each thread completion, is it going to hold the results? And after all the process finish, I can just loop future object to get the results right?

Without needing to know too much about the inner workings. You are given a future object, that at some point in time it will invoke the call method from the callable you pass in to the Executor. When the call method completes, the future will set the value that is associated to the future object (that value gets returned in with get()).

So there is a one-to-one relationship between the Future's youre given and the TaskWorker you create.

Also, there is no guarantee that process will run in order (1,2,3,4,etc), right? If that the case, then what is the best strategy if I want to associate each original request with the future result?

Edit: bjoern.bauer's resolution makes more sense, not sure why I over engineered that

John V.
+2  A: 

Also, there is no guarantee that process will run in order (1,2,3,4,etc), right? If that the case, then what is the best strategy if I want to associate each original request with the future result?

You cannot know the order in which the background threads are started and finished, but when you loop through your result-ArrayList you will get, of course, the results in the order you submitted them. The only thing that can happen here is that the .get() will block until the particular result of this future-object is available, if not already available.

bjoern.bauer
Oh I see. Is there a reason to worry here about using Arraylist instead of Vector regarding thread safe issue?
javaWorker
Also, of course I forgot to shutdown ExecutorService. Assume, i need to put them after the future-loop, right?
javaWorker
You don't need to worry about thread-safety of the result-ArrayList because it is only accessed from one thread (the main thread) and not from any of the background threads. You should shutdown the ExecutorService after the future-loop. Otherwise your program won't exit until the executor terminated all cached background threads.
bjoern.bauer