2010-05-12 5 views
10

Je tente d'utiliser des contrats à terme pour la première fois. Il semble intelligent que vous pouvez annuler un travail, mais cela ne fonctionne pas comme prévu. Dans l'exemple ci-dessous, seul le premier travail est annulé. Le reste est terminé. Ai-je mal compris l'utilisation des contrats à terme?futur accord/filetage

public class ThreadExample 
{ 
    public static void main(String[] args) throws InterruptedException, ExecutionException 
    { 
     int processors = Runtime.getRuntime().availableProcessors(); 
     System.out.println("Processors: " + processors); 
     ExecutorService es = Executors.newFixedThreadPool(processors); 
     int nowork = 10; 
     Future<Integer>[] workres = new Future[nowork]; 
     for(int i = 0; i < nowork; i++) 
     { 
      workres[i] = es.submit(new SomeWork(i)); 
     } 
     for(int i = 0; i < nowork; i++) 
     { 
      if(i % 2 == 0) 
      { 
       System.out.println("Cancel"); 
       workres[i].cancel(true); 
      } 
      if(workres[i].isCancelled()) 
      { 
       System.out.println(workres[i] + " is cancelled"); 
      } 
      else 
      { 
       System.out.println(workres[i].get()); 
      } 
     } 
     es.shutdown(); 
    } 
} 

class SomeWork implements Callable<Integer> 
{ 
    private int v; 
    public SomeWork(int v) 
    { 
     this.v = v; 
    } 

    @Override 
    public Integer call() throws Exception 
    { 
     TimeUnit.SECONDS.sleep(5); 
     System.out.println(v + " done at " + (new Date())); 
     return v; 
    } 
} 

La sortie:

Processors: 4 
Cancel 
[email protected] is cancelled 
4 done at Wed May 12 17:47:05 CEST 2010 
2 done at Wed May 12 17:47:05 CEST 2010 
1 done at Wed May 12 17:47:05 CEST 2010 
3 done at Wed May 12 17:47:05 CEST 2010 
1 
Cancel 
2 
3 
Cancel 
4 
5 done at Wed May 12 17:47:10 CEST 2010 
7 done at Wed May 12 17:47:10 CEST 2010 
8 done at Wed May 12 17:47:10 CEST 2010 
6 done at Wed May 12 17:47:10 CEST 2010 
5 
Cancel 
6 
7 
Cancel 
8 
9 done at Wed May 12 17:47:15 CEST 2010 
9 

Répondre

7

Le problème est que votre boucle d'annulation chevauche avec votre boucle get(), qui bloque. Je pense que vous voulez avoir 2 boucles, n'est-ce pas? Une boucle qui annule les emplois paires, puis une seconde boucle qui vérifie ceux qui sont annulés et ceux qui ne sont pas, puis get() en conséquence.

La façon dont il est écrit en ce moment, avant même que la boucle ait eu une chance d'annuler workres[2], il a vérifié et a demandé get() de workres[1].

Je pense que vous avez besoin de 3 phases:

1. The `submit()` loop 
2. The selective `cancel()` loop 
3. The selective `get()` loop (which blocks) 
+0

Merci! N'a pas pensé à get() étant une méthode qui bloque un problème. –

8

Le Future#cancel() ne mettra pas fin/interrompre les déjà en cours d'exécution emplois. Cela annulera uniquement les tâches qui ne sont pas encore en cours d'exécution.

Mise à jour: polygenelubricants clouée la racine causer vers le bas (+1): voici le code amélioré:

int processors = Runtime.getRuntime().availableProcessors(); 
System.out.println("Processors: " + processors); 
ExecutorService es = Executors.newFixedThreadPool(processors); 
int nowork = 10; 
Future<Integer>[] workers = new Future[nowork]; 

for (int i = 0; i < nowork; i++) { 
    final int ii = i; 
    workers[i] = es.submit(new Callable<Integer>() { 
     public Integer call() throws Exception { 
      return ii; 
     } 
    }); 
} 

for (int i = 0; i < nowork; i++) { 
    if (i % 2 == 0) { 
     System.out.println("Cancel worker " + i); 
     workers[i].cancel(true); 
    } 
} 

for (int i = 0; i < nowork; i++) { 
    if (workers[i].isCancelled()) { 
     System.out.println("Worker " + i + " is cancelled"); 
    } else { 
     System.out.println("Worker " + i + " returned: " + workers[i].get()); 
    } 
} 

es.shutdown(); 

Résultat:

 
Processors: 2 
Cancel worker 0 
Cancel worker 2 
Cancel worker 4 
Cancel worker 6 
Cancel worker 8 
Worker 0 is cancelled 
Worker 1 returned: 1 
Worker 2 is cancelled 
Worker 3 returned: 3 
Worker 4 is cancelled 
Worker 5 returned: 5 
Worker 6 is cancelled 
Worker 7 returned: 7 
Worker 8 is cancelled 
Worker 9 returned: 9 

(notez que c'est workers, pas workres) .

+0

« Si la tâche a déjà commencé, le paramètre mayInterruptIfRunning détermine si le thread d'exécuter cette tâche doit être interrompue pour tenter d'arrêter la tâche. » Imo cancel est un très mauvais mot/nom de méthode à utiliser si vous ne pouvez l'utiliser que sur des tâches qui ne sont pas encore exécutées:/ –

+0

Je trouve moi-même la différence entre 'cancel' et' interrupt' (ou 'abort' ou' terminate') pourtant assez clair. – BalusC

+0

Vous pouvez appeler '.cancel (true)' pour forcer un travail qui a commencé à interrompre. – Finbarr

Questions connexes