2009-03-12 8 views
2

Ich versuche, Port-Code von Java unter Verwendung von timers-scheduledexecutorservice mitPortieren von Code von Timern mit bis zu ScheduledExecutorService

Ich habe gerade Timer-Instanzen in der Klasse A ersetzen und den folgenden Anwendungsfall

class A { 

    public boolean execute() { 
     try { 
       Timer t = new Timer(); 
       t.schedule (new ATimerTask(), period, delay); 
     } catch (Exception e) { 
       return false; 
     } 
    } 

} 


class B { 

    public boolean execute() { 
     try { 
       Timer t = new Timer(); 
       t.schedule (new BTimerTask(), period, delay); 
     } catch (Exception e) { 
       return false; 
     } 
    } 

} 

Soll ich Klasse B mit ScheduledExecutorService und die ATimerTask und BTimerTask Klasse zu einer Runnable-Klasse machen, zB für

class B { 

    public boolean execute() { 
     try { 
       final ScheduledExecutorService scheduler = 
    Executors.newScheduledThreadPool(1); 

       scheduler.scheduleWithFixedDelay (new BRunnnableTask(), period, delay); 
     } catch (Exception e) { 
       return false; 
     } 
    } 

} 

Ist t sein richtiges.

BEARBEITEN: Eine der Hauptmotivation der Portierung ist, da Laufzeitausnahmen, die in TimerTask ausgelöst werden, diesen einen Thread beenden und nicht weiter geplant werden können. Ich möchte den Fall so vermeiden, dass ieven, wenn ich Laufzeitausnahme habe, der Thread weiter ausführen und nicht anhalten soll.

Antwort

5

HINWEIS: Die Art, wie Sie dies getan haben, wird Threads undicht werden!

Wenn Ihre Klasse B wird um und jede Instanz gehalten werden wird schließlich geschlossen oder stillgelegt oder freigegeben werden, würde ich es tun, wie folgt:

class B { 
    final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); 

    public boolean execute() { 
    try { 
     scheduler.scheduleWithFixedDelay(new BRunnnableTask(), period, delay); 
     return true; 
    } catch (Exception e) { 
     return false; 
    } 
    } 

    public void close() { 
    scheduler.shutdownNow(); 
    } 
} 

Wenn Sie diese Art geht nicht von Bereinigung auf jeden Fall, dann würde ich diese stattdessen tun:

class B { 
    static final ScheduledExecutorService SCHEDULER = Executors.newCachedThreadPool(); 

    public boolean execute() { 
    try { 
     SCHEDULER.scheduleWithFixedDelay(new BRunnnableTask(), period, delay); 
     return true; 
    } catch (Exception e) { 
     return false; 
    } 
    } 
} 

jeder ExecutorService Sie in Ihrem Code zuordnen ordnet einen einzigen Thread. Wenn Sie viele Instanzen Ihrer Klasse B erstellen, wird jeder Instanz eine Thread zugeordnet. Wenn diese Daten nicht schnell gesammelt werden, können viele tausend Threads zugewiesen werden (aber nicht verwendet, nur zugewiesen) und Sie können den gesamten Server zum Absturz bringen, was jeden Prozess auf der Maschine verhungern lässt, nicht nur Ihre eigene JVM. Ich habe es unter Windows gesehen und ich vermute, dass es auch auf anderen Betriebssystemen passieren kann.

Ein statischer Thread-Pool Cache ist sehr oft eine sichere Lösung, wenn Sie nicht beabsichtigen, Lifecycle-Methoden auf die einzelnen Objektinstanzen zu verwenden, da Sie nur so viele Fäden halten werden als tatsächlich sind und nicht ein Rennen für Jede Instanz, die Sie erstellen, ist noch nicht Garbage Collection.

3

Es sieht gut aus. Je nachdem, was Sie gerade tun, sollten Sie den Executor-Service als Mitglied beibehalten, damit Sie ihn erneut verwenden können. Außerdem können Sie eine ScheduledFuture von den Methoden scheduleXX() zurückholen. Dies ist nützlich, weil Sie get() aufrufen können, um alle Ausnahmen, die im zeitgesteuerten Thread auftreten, zur Behandlung zurück in Ihren Kontrollthread zu ziehen.

+0

Das ist sehr wichtig!Executoren sind im Allgemeinen zweifelhaft, wenn sie zum Wiederholen von Tasks verwendet werden, da sie Exceptions schlucken - nun, eigentlich wird die Exception nicht in der FutureTask gespeichert, aber da niemand get() aufruft, ist der Effekt der gleiche. –

1

Es gibt derzeit keine gute Möglichkeit, wiederkehrende Aufgaben im Executors-Framework zu behandeln.

Es wurde wirklich nicht mit diesem Anwendungsfall konzipiert, und es gibt keine realistische Möglichkeit, Ausnahmen zu verschlucken.

Wenn Sie es wirklich für sich wiederholende Aufgaben verwenden müssen, sollte jede Terminierung wie folgt aussehen:

scheduler.scheduleWithFixedDelay(new Runnable() { 
    public void run() { 
    try { 
     .. your normal code here... 
    } catch (Throwable t) { 
     // handle exceptions there 
    } 
    } 
}, period, delay); 
Verwandte Themen