Вызов метода на дату / время - PullRequest
2 голосов
/ 06 марта 2019

Я ищу современный способ выполнения данного метода в определенную дату / время (в частности, ZonedDateTime).

Мне известны класс Timer и библиотека Quartz , как показано здесь (темы включают полные решения):

Но эти потоки довольно старые и с тех пор не используют новые функции Java и элементы библиотеки. В частности, было бы очень удобно заполучить любой тип объекта Future, поскольку он предоставляет простой механизм их отмены.

Поэтому, пожалуйста, не предлагайте решения, включающие Timer или Кварц . Кроме того, я хотел бы иметь решение vanilla , не используя никаких внешних библиотек. Но не стесняйтесь также предлагать их ради Q & A.

1 Ответ

3 голосов
/ 06 марта 2019

ScheduledExecutorService

Вы можете использовать класс ScheduledExecutorService ( документация ), который доступен с Java 5. Он даст ScheduledFuture ( документация *)1009 *), который можно использовать для контроля выполнения и его отмены.

В частности, метод:

ScheduledFuture<?> schedule​(Runnable command, long delay, TimeUnit unit)

, который

Представляет одинзадача, которая становится активной после заданной задержки.

Но вы также можете посмотреть другие методы, в зависимости от фактического варианта использования (scheduleAtFixedRate и версий, принимающих Callable вместо * 1023).*).

Начиная с Java 8 (Streams, Lambdas, ...) этот класс становится еще более удобным благодаря доступности простых методов преобразования между старым TimeUnit и более новым ChronoUnit (дляваш ZonedDateTime), а также возможность предоставить Runnable command в качестве лямбды или ссылки на метод (потому что это FunctionalInterface).


Пример

Давайте получимпосмотрите на пример, делающий то, что вы просите:

// Somewhere before the method, as field for example
// Use other pool sizes if desired
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

public static ScheduledFuture<?> scheduleFor(Runnable runnable, ZonedDateTime when) {
    Instant now = Instant.now();
    // Use a different resolution if desired
    long secondsUntil = ChronoUnit.SECONDS.between(now, when.toInstant());

    return scheduler.schedule(runnable, secondsUntil, TimeUnit.of(ChronoUnit.SECONDS));
}

Вызов прост:

ZonedDateTime when = ...
ScheduledFuture<?> job = scheduleFor(YourClass::yourMethod, when);

Вы можете затемиспользуйте job, чтобы контролировать выполнение, а также отменить его, если это необходимо.Пример:

if (!job.isCancelled()) {
    job.cancel(false);
}

Примечания

Вы можете обменять параметр ZonedDateTime в методе на Temporal, тогда он также принимает другие форматы даты / времени.

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

scheduler.shutdown();

Обратите внимание, что мы используем Instant вместо ZonedDateTime, поскольку информация о зоне для нас не важна, еслиразница во времени рассчитывается правильно.Instant всегда представляет время в UTC, без каких-либо странных явлений, таких как DST .(Хотя это не имеет большого значения для этого приложения, оно просто чище).

...