Desidero utilizzare un CompletionService per elaborare i risultati da una serie di thread quando sono stati completati. Ho il servizio in un ciclo per prendere gli oggetti Future che fornisce man mano che diventano disponibili, ma non conosco il modo migliore per determinare quando tutti i thread hanno completato (e quindi per uscire dal ciclo):Come sapere quando un CompletionService ha finito di fornire risultati?
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
public class Bar {
final static int MAX_THREADS = 4;
final static int TOTAL_THREADS = 20;
public static void main(String[] args) throws Exception{
final ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(MAX_THREADS);
final CompletionService<Integer> service = new ExecutorCompletionService<Integer>(threadPool);
for (int i=0; i<TOTAL_THREADS; i++){
service.submit(new MyCallable(i));
}
int finished = 0;
Future<Integer> future = null;
do{
future = service.take();
int result = future.get();
System.out.println(" took: " + result);
finished++;
}while(finished < TOTAL_THREADS);
System.out.println("Shutting down");
threadPool.shutdown();
}
public static class MyCallable implements Callable<Integer>{
final int id;
public MyCallable(int id){
this.id = id;
System.out.println("Submitting: " + id);
}
@Override
public Integer call() throws Exception {
Thread.sleep(1000);
System.out.println("finished: " + id);
return id;
}
}
}
Ho provato a verificare lo stato di ThreadPoolExecutor, ma so che i metodi getCompletedTaskCount e getTaskCount sono solo approssimazioni e non dovrebbero essere considerati affidabili. C'è un modo migliore per assicurarmi di aver recuperato tutti i Futures dal CompletionService di contarli da soli?
Edit: Sia il link che Nobeh fornito, e this link suggeriscono che contando il numero di attività presentate, quindi chiamando prendere() che molte volte, è la strada da percorrere. Sono solo sorpreso che non ci sia un modo per chiedere al CompletionService o al suo Executor cosa rimane da restituire.
Grazie, nobile. Sembra che anche loro si colleghino semplicemente al conteggio dei thread, nel loro ciclo "for (int tasksHandled = 0; tasksHandled
L'esempio nell'API utilizza lo stesso approccio dell'esecuzione take() n volte di seguito. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorCompletionService.html –
Se i risultati di CompletionService in un thread diverso rispetto a quelli inviati a Exector, il thread è sicuro? – raffian