2011-01-05 11 views
0

Ich habe einige Diskussionen in dieser Richtung gesehen, aber keine spezifische Antwort auf meine Frage. Ich möchte eine Aufgabe neu starten, wenn ein Thread aufgrund einer nicht abgefangenen Ausnahme abstürzt. Ist es sicher, pool.execute (runnable) aus dem UncaughtExceptionHandler-Set des sterbenden Threads aufzurufen?Task von UncaughtExceptionHandler erneut ausführen?

Im Idealfall, wenn das thrownable eine RuntimeException ist, möchte ich einfach das runnable zum Pool, z.


pool = Executors.newFixedThreadPool(monitors.size(), new ThreadFactory() { 
    @Override 
    public Thread newThread(Runnable r) { 
     Thread thread = new Thread(r); 
     threadMap.put(thread, (Monitor)r); 
     thread.setName(((Monitor)r).getClusterName() + "-monitor"); 
     thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { 
      @Override 
      public void uncaughtException(Thread th, Throwable t) { 
       logger.error("Uncaught exception in thread: " + th.getName(), t); 
       if (t instanceof RuntimeException) { 
        Monitor m = threadMap.get(th); 
        if (m != null && m.runCount() < restartMax) { 
         logger.error("Restarting monitor due to uncaughtException: " + m.getClusterName()); 
         pool.execute(m); 
        }      } 
      }     
     }); 
     return thread; 
    }   
}); 

Gibt es einen besseren Weg oder einen sichereren Weg, dies zu tun?

Danke!

Antwort

1

Die sicherste Option wäre, nur eine Runtime Exception auszulösen, die fatal ist. Wenn eine Runtime Exception ignoriert werden kann, warum wird sie nicht abgefangen und fortgesetzt?

Es scheint, dass Ihre Thread-Map wie ein ThreadLocal aussieht. Es sieht so aus, dass ein Task, wenn er alle neustartMax verwendet, niemals einen Task erneut startet.

Die Art, wie ich dies tun würde, ist das Wrapping der ausführbaren Runnable.

public void submit(final Runnable runnable, final int restartMax) { 
    pool.submit(new Runnable() { 
     public void run() { 
      for(int i=0;i<restartMax;i++) 
       try { 
        runnable.run(); 
        break; 
       } catch (Exception e) { 
        log.error("Exception", e); 
       } 
     } 
    } 
} 
+0

Die threadMap ist nur um mir zu ermöglichen, den Monitor/Runnable, der dem Thread mit Ausnahme entspricht, zu erhalten. restartMax dient lediglich dazu, Threads, die unmittelbar auf einen dauerhaften Fehler stoßen, nicht unbegrenzt neu zu starten. Dieser Mechanismus soll eine vorübergehende Ausnahme wiederherstellen, die nicht explizit behandelt wurde. – batkins

0

Ihr Codebeispiel erfüllt nicht die Aufgabe, die Sie ansprechen möchten. Die Runnable, die an die ThreadFactory übergeben wird, ist nicht Ihre ausführbare Aufgabe, sondern eine interne Runnable, die vom ThreadPoolExecutor verwendet wird.

Sie sollten stattdessen in Erwägung ziehen, die Methode afterExecute() zu überschreiben. Diese Methode wird immer aufgerufen, und das erste Argument wird als runnable und das zweite Argument (Throwable) als die nicht abgefangene Ausnahme dargestellt. Nach execute() wird nicht die Ausnahme melden, wenn die Aufgabe entweder explizit von Ihnen mit einer FutureTask oder indirekt über submit() umschlossen wird. AfterExecute() würde also nur mit der Übergabe über execute() funktionieren.

protected void afterExecute(Runnable r, Throwable t) { 
    super.afterExecute(r, t); 
    if (t != null) { 
     Monitor m = (Monitor)r; 
     if (m.runCount() < restartMax) { 
      logger.error("Restarting monitor due to uncaughtException: " 
        + m.getClusterName()); 
      execute(m); // exception handling omitted 
     } 
    } 
} 
+0

Ja, ich bin sofort auf genau dieses Problem gestoßen. Zur Zeit benutze ich eine traditionelle neue Thread/setUncaughtExceptionHandler/start-Sequenz. Es scheint sowohl seltsam als auch kurzsichtig zu sein, dass Sie nicht auf das Runnable von Thread zugreifen können. Ich werde Ihren Vorschlag prüfen. Ich verwende weder FutureTask noch submit, also sollte das funktionieren. Vielen Dank! – batkins

+0

Auch wenn der Thread mit Ihrem übergebenen Runnable erstellt wurde, beachten Sie, dass es nur Ihre ** erste ** Aufgabe ist, die die Erstellung des Threads ausgelöst hat. Threads werden langlebig sein und mehrere Aufgaben ausführen. Daher werden Sie nicht in der Lage sein, das tatsächliche Runnable zu erhalten, das eine RuntimeException zuverlässig verursacht. – sjlee

Verwandte Themen