Класс библиотеки Java для обработки запланированного выполнения “обратных вызовов”?

StackOverflow https://stackoverflow.com/questions/614257

Вопрос

В моей программе есть компонент, получивший название Планировщик, который позволяет другим компонентам регистрировать моменты времени, в которые они хотят, чтобы их отозвали.Это должно работать очень похоже на службу cron в Unix, i.e.вы говорите Планировщику: "уведомляйте меня через десять минут после каждого полного часа".

Я понимаю, что в Java нет реальных обратных вызовов.

Вот мой подход, есть ли библиотека, которая уже делает это?Не стесняйтесь также предлагать улучшения.

Регистрировать вызовы для проходов Планировщика:

  • спецификация времени, содержащая час, минуту, секунду, год месяц, dom, dow, где каждый элемент может быть не указан, что означает "выполнять его каждый час / минуту и т.д." (точно так же, как crontabs)
  • объект, содержащий данные, которые сообщат вызывающему объекту, что делать, когда он получит уведомление от Планировщика.Планировщик не обрабатывает эти данные, просто сохраняет их и передает обратно после уведомления.
  • ссылка на вызывающий объект

При запуске или после нового запроса на регистрацию Планировщик запускается с объекта Calendar текущего системного времени и проверяет, есть ли в базе данных какие-либо записи, соответствующие этому моменту времени.Если таковые имеются, они выполняются, и процесс начинается сначала.Если таковых нет, время в объекте Calendar увеличивается на одну секунду и входные данные перепроверяются.Это повторяется до тех пор, пока не найдется одна или несколько совпадающих записей.(Моделирование дискретных событий)

Затем планировщик будет запоминать эту временную метку, переходить в режим сна и пробуждаться каждую секунду, чтобы проверить, есть ли она уже там.Если случается, что он просыпается, а время уже прошло, все начинается сначала, аналогично, если время пришло и задания были выполнены.


Редактировать:Спасибо, что указали мне на Quartz.Однако я ищу что-то гораздо меньшее.

Это было полезно?

Решение

Если ваши потребности просты, рассмотрите возможность использования java.утилита.Таймер:

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

}

Как и было отмеченный, тот Служба исполнителя из java.util.параллельный предлагает более богатый API, если вам это нужно.

Другие советы

Поиск Кварц

Если ваши объекты точно знают отдельные моменты времени, которые они хотят выполнить, то вы могли бы использовать java.util.concurrent.ScheduledExecutorService.Затем они просто звонят:

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

Вам нужно будет только использовать Quartz если вы хотите, чтобы сам планировщик обрабатывал такие функции, как "выполняться каждые 5 секунд", или если вам нужно сложное поведение в связи с пропущенными исполнениями, или сохранение журнала аудита выполнения.

На самом деле вы можете тривиально повторно использовать кварцевые CronTrigger класс, чтобы получить "время следующего выполнения".Класс полностью автономен и не зависит от того, вызывается ли он изнутри Quartz "контекст".Как только у вас будет следующее время выполнения в качестве Date или long, вы можете просто использовать Java ScheduledExecutorService как указано выше

Кварц является большим и очевидным локомотивом в этой области, но есть несколько альтернатив для изучения.

Cron4j ( Крон4j ) это достаточно приличная библиотека, которая немного более легкая, чем Quartz.Он предоставляет хорошую документацию и будет делать то, что вы хотите.

Вероятно, более интересным является то, что если вы хотите использовать библиотеку, которая лучше подходит для библиотек параллелизма Java (в частности, Executors и ScheduledExecutors), то ХА-JDBC имеет CronExecutorService Кронекс- Сервис интерфейс, реализованный его CronThreadPoolExecutor - исполнитель.Теперь, что интересно, у него есть зависимость от Quartz (для предоставления класса CronExpression), но я нахожу, что эти два вместе работают лучше, чем просто Quartz по отдельности.Если вам не нужны большие зависимости, легко извлечь несколько классов из Quartz и HA-JDBC, которые позволяют это сделать.

Поскольку вы хотите что-то намного меньшее (только что заметил вашу правку), возьмите CronExpression из Quartz и два класса HA-JDBC, о которых я упоминал выше.Этого будет достаточно.

Я бы настоятельно рекомендовал cron4j ( крон4j ) (уже упоминалось) поверх Quartz, если только вам абсолютно не нужны некоторые из более продвинутых и сложных функций Quartz.Cron4j хорошо фокусируется на том, что он должен делать, имеет приличную документацию и не является решением для кухонной мойки.

Кварцевый планировщик обычно рекомендуется.

Не могу поверить, java.util.Таймер был выбран в качестве ответа.Кварц действительно гораздо лучший выбор.

Большое преимущество quartz перед java.util.Timer заключается в том, что с quartz задания могут храниться в базе данных.В результате одна jvm может планировать, а другая может выполняться.Также (очевидно) запрос сохраняется при перезапуске jvm.

Вероятно, более интересным является то, что если вы хотите использовать библиотеку, которая лучше подходит для библиотек параллелизма Java (в частности, Executors и ScheduledExecutors), то HA-JDBC имеет интерфейс CronExecutorService, реализованный его CronThreadPoolExecutor .Теперь, что интересно, у него есть зависимость от Quartz (для предоставления класса CronExpression), но я нахожу, что эти два вместе работают лучше, чем просто Quartz по отдельности.Если вам не нужны большие зависимости, легко извлечь несколько классов из Quartz и HA-JDBC, которые позволяют это сделать.

Я просто хотел сказать, что я попробовал извлечь эти классы, и это сработало!Мне нужны были эти три класса:

  • КронЭкспрессия (кварц)
  • CronThreadPoolExecutor (ha-jdbc)
  • Демон-потоковая фабрика (ha-jdbc)

И мне нужно было только внести эти незначительные изменения:

  • Удаление регистратора из CronThreadPoolExecutor (он был создан, но никогда не использовался)
  • Переместил константу YEAR_TO_GIVEUP_SCHEDULING_AT из CronTrigger в CronExpression

Я был в восторге от того, что не застрял в клубке зависимостей.Поздравляем авторов класса!

И это работало как чемпион.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top