Question

J'ai soumis une tâche à l'aide d'exécuteurs et j'ai besoin qu'elle s'arrête après un certain temps (par exemple 5 minutes). J'ai essayé de faire comme ça:

   for (Future<?> fut : e.invokeAll(tasks, 300, TimeUnit.SECONDS)) {
         try {
             fut.get(); 
         } catch (CancellationException ex) {
             fut.cancel(true);   
             tasks.clear();
         } catch(ExecutionException ex){
             ex.printStackTrace(); //FIXME: gestita con printstack       
         }
   }

Mais je reçois toujours une erreur: j'ai un vecteur partagé qui doit être modifié par les tâches, puis lu par un fil de discussion, et même si j'arrête toute la tâche, si le délai d'attente est écoulé, je reçois:

Exception in thread "Thread-1" java.util.ConcurrentModificationException

Quelque chose ne va pas? Comment puis-je arrêter les tâches soumises qui fonctionnent encore après 5 minutes?

Était-ce utile?

La solution

Ce n'est pas parce que vous appelez cancel () sur Future que la tâche s'arrête automatiquement. Vous devez effectuer certains travaux dans la tâche pour vous assurer qu'elle va s'arrêter:

  • Utilisez cancel (true) pour qu'une interruption soit envoyée à la tâche.
  • Traitement de InterruptedException . Si une fonction de votre tâche génère une InterruptedException , veillez à quitter correctement le système dès que possible après avoir intercepté l'exception.
  • Vérifiez périodiquement Thread.currentThread (). isInterrupted () si la tâche effectue un calcul continu.

Par exemple:

class LongTask implements Callable<Double> {
    public Double call() {

         // Sleep for a while; handle InterruptedException appropriately
         try {
             Thread.sleep(10000);
         } catch (InterruptedException ex) {
             System.out.println("Exiting gracefully!");
             return null;
         }


         // Compute for a while; check Thread.isInterrupted() periodically
         double sum = 0.0;
         for (long i = 0; i < 10000000; i++) {
             sum += 10.0
             if (Thread.currentThread().isInterrupted()) {
                 System.out.println("Exiting gracefully");
                 return null;
             }
         }

         return sum;
    } 
}

En outre, comme d'autres publications l'ont mentionné: ConcurrentModificationException peut être levé même si vous utilisez la classe Vector thread-safe, car les itérateurs que vous obtenez à partir de Vector ne sont pas thread-safe, et doivent donc être synchronisés. La boucle for avancée utilise des itérateurs, alors faites attention:

final Vector<Double> vector = new Vector<Double>();
vector.add(1.0);
vector.add(2.0);

// Not thread safe!  If another thread modifies "vector" during the loop, then
// a ConcurrentModificationException will be thrown.
for (Double num : vector) {
    System.out.println(num);
}

// You can try this as a quick fix, but it might not be what you want:
synchronized (vector) {    // "vector" must be final
    for (Double num : vector) {
        System.out.println(num);
    }
}

Autres conseils

L'exception ConcurrentModificationException provient de votre appel à tasks.clear () pendant que votre Exceutors parcourt vos tâches Vector . Ce que vous pouvez essayer de faire, c'est d'appeler shutdownNow () sur votre service d'exécution (

)

Le cas le plus courant pour ConcurrentModificationException est lorsque le vecteur est en cours de modification en même temps qu'il est itéré. Cela se fera souvent en un seul fil. Vous devez conserver un verrou sur le vecteur pour l'ensemble de l'itération (en prenant soin de ne pas vous bloquer).

fut.get () est un appel bloquant. Même après l'expiration du délai, vous bloquez jusqu'à ce que la tâche soit terminée. Si vous souhaitez vous arrêter le plus près possible des 5 minutes, vous devez vérifier l'indicateur d'interruption. Je vous recommande simplement de le faire à l'aide de la méthode Thread.isInterrupted () qui préserve l'état d'interruption. Si vous souhaitez simplement vous arrêter immédiatement et n'avez pas besoin de nettoyer un état, lancez une exception qui sera interceptée par le futur et vous sera indiquée comme une ExecutionException.

fut.cancel (true) ne fait rien car la méthode invokeAll () l'a déjà fait pour vous.

Sauf si vous utilisez les " tâches " Si vous collectez quelque part ailleurs, vous n'avez probablement pas besoin d'appeler clear () dessus. Cela ne va pas être la source de votre problème puisque la méthode invokeAll () est faite avec la liste au moment où vous appelez clear (). Toutefois, si vous devez commencer à former une liste de nouvelles tâches à exécuter, je vous suggère de former une nouvelle liste de tâches et de ne pas utiliser une ancienne liste de nouvelles tâches.

Malheureusement, je n'ai pas de réponse à votre problème. Je ne vois pas assez d'informations ici pour le diagnostiquer. Rien dans l'extrait de code que vous avez fourni n'indique une utilisation incorrecte (uniquement inutile) des classes / méthodes de la bibliothèque. Peut-être que si vous incluiez une trace de pile complète au lieu de l'erreur d'une ligne.

Placez le fut.cancel (true); dans le bloc finally

.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top