2009-03-12 7 views
2

Je suis en train de code le port d'utiliser java timers à l'aide scheduledexecutorserviceCode portage de l'utilisation des minuteries pour scheduledexecutorservice

Je l'utilisation suivant le cas

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

} 

Dois-je remplacer seulement les instances de minuterie en classe A et classe B avec ScheduledExecutorService et faire la classe ATimerTask et BTimerTask à une classe Runnable, par exemple

class B { 

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

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

} 

est t son correct.

EDIT: L'une des principales motivations du portage est que les exceptions d'exécution lancées dans TimerTask détruisent un thread et ne peuvent plus être planifiées. Je veux éviter le cas afin que ieven si j'ai l'exception d'exécution le fil devrait continuer à s'exécuter et ne pas s'arrêter.

Répondre

5

REMARQUE: La façon dont vous avez fait cela entraînera des fuites de fils!

Si votre classe B sera conservée autour et chaque instance finira par être fermé ou fermé vers le bas ou libéré, je le ferais comme ceci:

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

Si vous ne faites pas ce genre de nettoyage sur chaque instance, alors je place ce faire:

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

chaque ExecutorService vous allouez dans votre code attribue un seul Thread. Si vous effectuez plusieurs instances de votre classe B, un numéro Thread sera attribué à chaque instance. Si ceux-ci ne sont pas collectés rapidement, vous pouvez vous retrouver avec des milliers de threads alloués (mais pas utilisés, juste alloués) et vous pouvez planter tout votre serveur, affamant chaque processus sur la machine, pas seulement votre propre JVM. Je l'ai vu se produire sur Windows et je pense que cela peut arriver sur d'autres systèmes d'exploitation. Un pool de threads statique mis en cache est très souvent une solution sûre lorsque vous n'avez pas l'intention d'utiliser des méthodes de cycle de vie sur les instances d'objet individuelles, car vous ne gardez que les threads en cours d'exécution et non un pour chaque instance que vous créez n'est pas encore collectée.

3

Cela semble correct. En fonction de ce que vous faites, vous pouvez conserver le service d'exécution en tant que membre afin de pouvoir l'utiliser à nouveau. En outre, vous pouvez obtenir un ScheduledFuture à partir des méthodes scheduleXX(). Ceci est utile car vous pouvez appeler get() pour retirer toutes les exceptions qui se produisent dans le thread temporisé vers votre thread de contrôle pour la gestion.

+0

Ceci est très important!Les exécuteurs en général sont douteux lorsqu'ils sont utilisés pour répéter des tâches parce qu'ils avalent des exceptions - et non réellement, l'exception est stockée dans la FutureTask, mais comme personne ne l'appelle get() lors d'une tâche répétée, l'effet est le même. –

1

Il n'existe actuellement aucun bon moyen de gérer les tâches répétitives dans l'infrastructure Executors.

Il n'a vraiment pas été conçu en pensant à ce cas d'utilisation, et il n'y a aucun moyen réaliste d'éviter de déglutir des exceptions.

Si vous devez vraiment utiliser pour répéter des tâches, chaque planification devrait ressembler à ceci:

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