2009-03-12 7 views
11

J'ai vu ce dans la documentation java: ScheduledAtFixedRate, il ditComment replanifier une tâche à l'aide d'un ScheduledExecutorService?

Si l'exécution de la tâche rencontre une exception, ultérieures exécutions sont supprimées

Je ne veux pas que cela se produise dans ma demande. Même si je vois une exception, je voudrais toujours que les exécutions suivantes se produisent et continuent. Comment puis-je obtenir ce comportement de ScheduledExecutorService.

+1

Je préfère la solution décrite dans [blog CosmoCode ] (http://www.cosmocode.de/en/blog/schoenborn/2009-12/17-uncaught-exceptions-in-scheduled-tasks) – Chobicus

+0

La solution dans _CosmoCode blog_ ** bloque ** (en utilisant 'future. get(); '), qui est contre le point d'exécution asynchrone fourni par le' Executor's. – user454322

Répondre

7

Surround la méthode Callable.call ou la méthode Runnable.run avec un try/catch ...

par exemple:

public void run() 
{ 
    try 
    { 
     // ... code 
    } 
    catch(final IOException ex) 
    { 
     // handle it 
    } 
    catch(final RuntimeException ex) 
    { 
     // handle it 
    } 
    catch(final Exception ex) 
    { 
     // handle it 
    } 
    catch(final Error ex) 
    { 
     // handle it 
    } 
    catch(final Throwable ex) 
    { 
     // handle it 
    } 
} 

Notez que la capture autre chose que ce que le compilateur vous dit aussi (l'exception IOException dans mon exemple) n'est pas une bonne idée, mais il y a des fois, et cela ressemble à l'un d'entre eux, que ça peut marcher si vous le manipulez correctement. Rappelez-vous que des choses comme Erreur sont très mauvaises - la VM a manqué de mémoire etc ... alors faites attention à la façon dont vous les manipulez (c'est pourquoi je les ai séparés dans leurs propres gestionnaires plutôt que de faire des catch (Final Throwable ex) et rien d'autre).

+0

Notez que si vous n'attrapez pas throwable dans une tâche planifiée répétitive et qu'un OOME se produit, vous ne le découvrirez jamais (à moins que quelque chose n'appelle get() sur le ScheduledFuture et la journalisation ExecutionExceotions –

+0

Eh bien alors ... devinez vous devez ... ick :-) Je vais vérifier puis mettre à jour ma réponse - thx – TofuBeer

+0

Est-ce que l'exécution suivante est arrêtée en raison de la terminaison du thread particulier? Si la taille du pool de threads est supérieure à 1, ce qui est généralement le cas, pourquoi l'exécution de la tâche ScheduledExecutorService ne peut-elle pas être exécutée à l'aide d'un thread différent? – RRM

1

J'ai eu le même problème. J'ai également essayé ce bloc try dans la méthode run() mais cela ne fonctionne pas.

Je l'ai fait quelque chose fonctionne jusqu'à présent:

import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.LinkedBlockingQueue; 

public class Test2 { 

    static final ExecutorService pool = Executors.newFixedThreadPool(3); 

    static final R1 r1 = new R1(); 
    static final R2 r2 = new R2(); 

    static final BlockingQueue deadRunnablesQueue = new LinkedBlockingQueue<IdentifiableRunnable>(); 

    static final Runnable supervisor = new Supervisor(pool, deadRunnablesQueue); 

    public static void main(String[] args) { 
     pool.submit(r1); 
     pool.submit(r2); 
     new Thread(supervisor).start(); 
    } 

    static void reSubmit(IdentifiableRunnable r) { 
     System.out.println("given to an error, runnable [" + r.getId() 
       + "] will be resubmited"); 
     deadRunnablesQueue.add(r); 
    } 

    static interface IdentifiableRunnable extends Runnable { 
     String getId(); 
    } 

    static class Supervisor implements Runnable { 
     private final ExecutorService pool; 
     private final BlockingQueue<IdentifiableRunnable> deadRunnablesQueue; 

     Supervisor(final ExecutorService pool, 
       final BlockingQueue<IdentifiableRunnable> deadRunnablesQueue) { 
      this.pool = pool; 
      this.deadRunnablesQueue = deadRunnablesQueue; 
     } 

     @Override 
     public void run() { 
      while (true) { 
       IdentifiableRunnable r = null; 
       System.out.println(""); 
       System.out 
         .println("Supervisor will wait for a new runnable in order to resubmit it..."); 
       try { 
        System.out.println(); 
        r = deadRunnablesQueue.take(); 
       } catch (InterruptedException e) { 
       } 
       if (r != null) { 
        System.out.println("Supervisor got runnable [" + r.getId() 
          + "] to resubmit "); 
        pool.submit(r); 
       } 
      } 
     } 
    } 

    static class R1 implements IdentifiableRunnable { 
     private final String id = "R1"; 
     private long l; 

     @Override 
     public void run() { 
      while (true) { 
       System.out.println("R1 " + (l++)); 
       try { 
        Thread.currentThread().sleep(5000); 
       } catch (InterruptedException e) { 
        System.err.println("R1 InterruptedException:"); 
       } 
      } 
     } 

     public String getId() { 
      return id; 
     } 
    } 

    static class R2 implements IdentifiableRunnable { 
     private final String id = "R2"; 
     private long l; 

     @Override 
     public void run() { 
      try { 
       while (true) { 
        System.out.println("R2 " + (l++)); 
        try { 
         Thread.currentThread().sleep(5000); 
        } catch (InterruptedException e) { 
         System.err.println("R2 InterruptedException:"); 
        } 
        if (l == 3) { 
         throw new RuntimeException(
           "R2 error.. Should I continue to process ? "); 
        } 
       } 
      } catch (final Throwable t) { 
       t.printStackTrace(); 
       Test2.reSubmit(this); 
      } 
     } 

     public String getId() { 
      return id; 
     } 
    } 

} 

Vous pouvez essayer de commenter Test2.reSubmit (cela) pour voir que sans elle, R2 cessera de fonctionner.

+0

Clarification: en fait ScheduledExecutorService fonctionne avec try block dans la méthode run(). L'exemple ci-dessus est basé sur ExecutorService à la place. – Rodolfo

+0

Merci de partager votre code. C'est un bon exemple cependant, semble trop compliqué. – user454322

2

Essayez VerboseRunnable classe de jcabi-log, qui fait l'emballage proposé par TofuBeer:

import com.jcabi.log.VerboseRunnable; 
Runnable runnable = new VerboseRunnable(
    Runnable() { 
    public void run() { 
     // do business logic, may Exception occurs 
    } 
    }, 
    true // it means that all exceptions will be swallowed and logged 
); 

Maintenant, quand quelqu'un appelle runnable.run() sans exception sont jetés. Au lieu de cela, ils sont avalés et enregistrés (à SLF4J).

+0

Nice, 'Exception's sont avalés en utilisant' VerboseRunnable', donc les tâches suivantes seront exécutées. – user454322

1

Si tout ce que vous voulez est exécutions ultérieures à se produire et continuer même après des exceptions, ce code devrait fonctionner.

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();  

Runnable task = new Runnable() {  
    @Override 
    public void run() { 
    try{ 
     System.out.println(new Date() + " printing"); 
     if(true) 
     throw new RuntimeException(); 

    } catch (Exception exc) { 
     System.out.println(" WARN...task will continiue"+ 
      "running even after an Exception has araised"); 
    } 
    }  
}; 

executor.scheduleAtFixedRate(task, 0, 3, TimeUnit.SECONDS); 

Si un Throwable autre que Exception a eu lieu, vous voudrez peut-être pas les exécutions suivantes sont exécutées.

Voici la sortie

ven 23 novembre 2012 12:09:38 JST impression
... _WARN tâche sera continiuerunning même après une exception a soulevé
Ven 23 novembre 12:09:41 JST 2012 impression
_WARN ... tâche va continuer même après une exception a soulevé
Fri Nov 23 12:09:44 JST 2012 impression
_WARN ...tâche continiuerunning même après une Exception a levé
Ven 23 novembre 2012 12:09:47 JST impression
_WARN ... tâche continiuerunning même après une exception a soulevé

Questions connexes