Question

Mon programme a un composant - appelé le planificateur - qui permet aux autres composants d’enregistrer les instants auxquels ils souhaitent être rappelés. Cela devrait fonctionner un peu comme le service Unix cron, i. e. vous dites au planificateur de m'avertir toutes les heures pleines après dix minutes.

Je me rends compte qu'il n'y a pas de réel callback en Java.

Voici mon approche, y at-il une bibliothèque qui fait déjà ce genre de choses? N'hésitez pas à proposer des améliorations également.

Enregistrer l'appel sur les passes du planificateur:

  • une spécification de temps contenant heure, minute, seconde, année mois, dom, dow, où chaque élément peut être non spécifié, ce qui signifie "l'exécuter toutes les heures / minutes, etc." (comme les crontabs)
  • un objet contenant des données qui diront à l'objet appelant quoi faire lorsqu'il est averti par le planificateur. Le planificateur ne traite pas ces données, il les stocke et les renvoie après notification.
  • une référence à l'objet appelant

Au démarrage, ou après une nouvelle demande d'enregistrement, le planificateur commence par un objet Calendrier de l'heure système actuelle et vérifie si des entrées de la base de données correspondent à ce moment. S'il y en a, ils sont exécutés et le processus recommence. S'il n'y en a pas, l'heure dans l'objet Calendar est incrémentée d'une seconde et les entrées sont revérifiées. Cela se répète jusqu'à ce qu'une ou plusieurs entrées correspondent. (Simulation d'événements discrets)

Le planificateur se souviendra ensuite de cet horodatage, de son sommeil et de son réveil toutes les secondes pour vérifier s’il est déjà là. S'il se réveille et que le temps est déjà passé, il recommence, de même que si le temps est venu et que les tâches ont été exécutées.

Modifier : Merci de m'avoir dirigé vers Quartz. Je cherche cependant quelque chose de beaucoup plus petit.

Était-ce utile?

La solution

Si vos besoins sont simples, envisagez d'utiliser java .util.Timer :

public class TimerDemo {

  public static void main(String[] args) {
    // non-daemon threads prevent termination of VM
    final boolean isDaemon = false;
    Timer timer = new Timer(isDaemon);

    final long threeSeconds = 3 * 1000;
    final long delay = 0;
    timer.schedule(new HelloTask(), delay, threeSeconds);

    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.MINUTE, 1);
    Date oneMinuteFromNow = calendar.getTime();

    timer.schedule(new KillTask(timer), oneMinuteFromNow);
  }

  static class HelloTask extends TimerTask {
    @Override
    public void run() {
      System.out.println("Hello");
    }
  }

  static class KillTask extends TimerTask {

    private final Timer timer;

    public KillTask(Timer timer) {
      this.timer = timer;
    }

    @Override
    public void run() {
      System.out.println("Cancelling timer");
      timer.cancel();
    }
  }

}

As a été noté , ExecutorService sur < a href = "http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-frame.html" rel = "nofollow noreferrer"> java.util.concurrent offre une API plus riche si vous en avez besoin.

Autres conseils

Recherche Quartz

Si vos objets connaissent exactement les moments précis dans lesquels ils souhaitent être exécutés, vous pouvez utiliser un java.util.concurrent.ScheduledExecutorService . Ensuite, ils appellent simplement:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
long timeToExecute = ... //read from DB? use CronTrigger?
long delayToExecution = timeToExecute - System.currentTimeMillis();
scheduler.schedule(aRunnable, delayToExecution, TimeUnit.MILLISECONDS);

Vous n'avez besoin d'utiliser Quartz que si vous souhaitez que le planificateur lui-même gère des fonctionnalités telles que "exécuter toutes les 5 secondes" ou si vous souhaitez un comportement complexe en ce qui concerne les exécutions manquées ou la persistance de l'exécution. la piste d'audit d'exécution.

Vous pouvez réellement réutiliser trivialement la classe CronTrigger de Quartz pour obtenir un "prochain temps d'exécution". La classe est complètement autonome et ne dépend pas de son appel depuis le Quartz "context". Une fois que vous avez la prochaine heure d’exécution sous la forme Date ou long , vous pouvez simplement utiliser Java ScheduledExecutorService comme ci-dessus

.

Quartz est le moteur le plus important et le plus évident dans ce domaine, mais il existe quelques alternatives à explorer. .

Cron4j est une bibliothèque assez correcte, un peu plus légère que Quartz. Il fournit une bonne documentation et fera ce que vous voulez.

Probablement plus intéressant si vous voulez utiliser une bibliothèque qui correspond mieux aux bibliothèques de concurrence de Java (en particulier Executors et ScheduledExecutors), alors HA-JDBC a un CronExecutorService , implémentée par son CronThreadPoolExecutor . Il est intéressant de noter qu’il dépend actuellement de Quartz (pour fournir la classe CronExpression), mais j’aperçois que les deux ensembles fonctionnent mieux que le seul Quartz. Si vous ne voulez pas de grandes dépendances, il est facile d'extraire la poignée de classes de Quartz et de HA-JDBC qui rendent cela possible.

Puisque vous voulez quelque chose de beaucoup plus petit (venez de remarquer votre modification), prenez CronExpression de Quartz et les deux classes HA-JDBC que j'ai mentionnées ci-dessus. Ça va le faire.

Je recommanderais vivement cron4j (déjà mentionné) sur Quartz, sauf si vous avez absolument besoin certaines des fonctionnalités plus avancées et complexes de Quartz. Cron4j se concentre bien sur ce qu’il est censé faire, dispose d’une documentation correcte et n’est pas une solution d’évier de cuisine.

Un

planificateur à quartz est généralement recommandé.

Je ne peux pas croire que java.util.Timer a été voté comme la réponse. Le quartz est vraiment un meilleur choix.

Un gros avantage du quartz par rapport à java.util.Timer est qu’avec le quartz, les travaux peuvent être stockés dans la base de données. En conséquence, un JVM peut être programmé et un autre peut être exécuté. De plus (évidemment), la requête survit après les redémarrages de jvm.

  

Probablement plus intéressant si vous voulez utiliser une bibliothèque qui convient mieux aux bibliothèques de concurrence de Java (en particulier Executors et ScheduledExecutors), alors HA-JDBC possède une interface CronExecutorService, implémentée par son CronThreadPoolExecutor. Il est intéressant de noter qu’il dépend actuellement de Quartz (pour fournir la classe CronExpression), mais j’aperçois que les deux ensembles fonctionnent mieux que le seul Quartz. Si vous ne voulez pas de grandes dépendances, il est facile d'extraire la poignée de classes de Quartz et de HA-JDBC qui rendent cela possible.

Je voulais juste dire que j'ai essayé d'extraire ces cours et que ça a fonctionné! J'avais besoin de ces trois cours:

  • CronExpression (quartz)
  • CronThreadPoolExecutor (ha-jdbc)
  • DaemonThreadFactory (ha-jdbc)

Et il ne me restait plus qu'à faire ces petites modifications:

  • Suppression de l'enregistreur de CronThreadPoolExecutor (il a été créé mais n'a jamais été utilisé)
  • Déplacement de la constante YEAR_TO_GIVEUP_SCHEDULING_AT de CronTrigger vers CronExpression

J'ai été ravi de ne pas m'être retrouvé coincé dans un enchevêtrement de dépendances. Félicitations aux auteurs de la classe!

Et ça marche comme un champion.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top