2009-03-12 10 views
11

vi esto en la documentación de Java: ScheduledAtFixedRate, que dice¿Cómo reprogramar una tarea usando un ScheduledExecutorService?

Si cualquier ejecución de la tarea encuentra una excepción, posteriores ejecuciones se suprimen

no quiero que esto suceda en mi aplicación. Incluso si veo una excepción, siempre desearía que las ejecuciones posteriores tuvieran lugar y continuara. ¿Cómo puedo obtener este comportamiento desde ScheduledExecutorService?

+1

prefiero solución descrita en [Blog CosmoCode ] (http://www.cosmocode.de/en/blog/schoenborn/2009-12/17-uncaught-exceptions-in-scheduled-tasks) – Chobicus

+0

La solución en _CosmoCode blog_ ** bloquea ** (usando 'future. get(); '), que está contra el punto de ejecución asíncrona proporcionada por el' Executor's. – user454322

Respuesta

7

Surround el método Callable.call o el método Runnable.run con un try/catch ...

por ejemplo:

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 
    } 
} 

Tenga en cuenta que la captura aparte de la que el compilador le dice nada demasiado (IOException en mi muestra) no es una buena idea, pero hay algunas veces, y esto suena como uno de ellos, que puede funcionar si lo maneja correctamente.

Recuerda que las cosas como Error son muy malas: la VM se quedó sin memoria, etc. ... así que ten cuidado de cómo manejarlas (por eso las separé en sus propios manejadores en lugar de solo atraparlas) ex) y nada más).

+0

Tenga en cuenta que si no detecta throwable en una tarea programada repetitiva y se produce un OOME, nunca se enterará (a menos que algo llame a get() en ScheduledFuture y logging ExecutionExceotions –

+0

Bien, entonces ... supongo tienes que ... ick :-) Verificaré y luego actualizaré mi respuesta - thx – TofuBeer

+0

¿Está deteniendo la ejecución posterior debido a la terminación del hilo en particular? Si el tamaño del grupo de subprocesos es mayor que 1, que es mayormente cierto, ¿por qué no es posible que la implementación de ScheduledExecutorService intente ejecutar la tarea utilizando un subproceso diferente? – RRM

1

Tuve el mismo problema. También probé ese intento de bloquear dentro del método run() pero no funciona.

Así que hice algo está funcionando hasta ahora:

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; 
     } 
    } 

} 

Usted puede tratar de comentar Test2.reSubmit (este) para ver que sin ella, R2 dejará de funcionar.

+0

Aclaración: en realidad ScheduledExecutorService funciona con try block dentro del método run(). El ejemplo anterior se basa en ExecutorService en su lugar. – Rodolfo

+0

Gracias por compartir su código. Sin embargo, es un buen ejemplo, parece complicado. – user454322

2

Trate VerboseRunnable clase de jcabi-log, lo que hace la envoltura sugerido por 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 
); 

Ahora, cuando alguien llama runnable.run() no se lanzan excepciones. En cambio, son tragados y registrados (a SLF4J).

+0

Bueno, 'Exception's se traga usando' VerboseRunnable', por lo que se ejecutarán las tareas siguientes. – user454322

1

Si todo lo que quiere es ejecuciones subsiguientes para ocurrir y continuar incluso después de las excepciones, este código debería funcionar.

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 se ha producido un Throwable que no sea Exception puede que no desee ejecuciones posteriores se ejecutan.

Aquí está la salida

Vie Nov 23 de 2012 12:09:38 JST impresión
... _WARN tarea continiuerunning incluso después de una excepción se ha planteado
Vie Nov 23 de 12:09:41 JST 2012 impresión
_WARN ... la tarea continuará ejecutándose incluso después de que se haya producido una excepción
vie 23 de noviembre 12:09:44 JST 2012 impresión
_WARN ...tarea continiuerunning incluso después de una excepción ha planteado
Vie Nov 23 de 2012 12:09:47 JST impresión
_WARN ... tarea continiuerunning incluso después de una excepción ha planteado

Cuestiones relacionadas