предисловие
задача на времяобычно существуютСредний и крупный корпоративный класспроект, чтобы уменьшитьсервер,база данныхдавление, часто сзадача на времяспособ завершить некоторую бизнес-логику.
Статьи из этой серии
- Actual Spring Boot 2.0 Series (1) — Создание образов Docker с помощью Gradle
- Actual Spring Boot 2.0 Series (2) — глобальная обработка исключений и тестирование
- Actual Spring Boot 2.0 Series (3) — Подробное объяснение асинхронных вызовов с использованием @Async
- Actual Spring Boot 2.0 Series (4) — Использование WebAsyncTask для обработки асинхронных задач
- Actual Spring Boot 2.0 Series (5) — прослушиватель, сервлет, фильтр и перехватчик
- Actual Spring Boot 2.0 Series (6) — несколько реализаций одномашинных задач синхронизации
Общее этосистема финансовых услугPush-обратный вызов.Как правило, заказ платежной системы не получает содержание обратного успешного обратного вызова.непрерывный обратный вызов, этот обратный вызов обычнозадача на времяЧто нужно сделать.
И естьгенерация отчета, мы вообщенебольшой трафикКогда эта операция завершена, вы также можете использоватьзадача на времяЧто нужно сделать.
текст
Несколько способов планирования задач
Timer
ЭтоJava
автономныйjava.util.Timer
класс, который позволяет планироватьjava.util.TimerTask
Задача. Использование этого метода позволяет вашей программе следовать определенномуЧастотавыполнить, но не вуказанное времябегать. Сейчас вообще используется меньше.
ScheduledExecutorService
JDK
Класс, который поставляется с ним, основан наПул потоковРазработанный класс задач на время, каждыйРасписание задачбудет выделеноПул потоководин изнитьвыполнить. То есть задачапараллельное выполнение, независимо друг от друга.
Spring Task
Spring 3.0
принести позжеTask
,служба поддержкиМногопоточностьрасписание, которое можно рассматривать каклегкийизQuartz
, и используя болееQuartz
Гораздо проще, но подходит дляодин узелизПланирование задач по расписанию.
Quartz
Этоболее могущественныйПланировщик, который позволяет вашей программе выполняться в указанное время или с определенной частотой, может быть настроеннемного сложно.Quartz
мощный, можно комбинироватьбаза данныхДелатьУпорство,провестираспределенныйизПланирование задержки задачи.
Введение в выражения Cron
Cron
выражение представляет собой строку, начинающуюся с5
или6
Кусоккосмосразделенный, разделенный6
или7
Кусокплощадь, каждое поле представляет значение,Cron
Существует два следующих формата синтаксиса:
- Seconds Minutes Hours DayofMonth Month DayofWeek Year
- Seconds Minutes Hours DayofMonth Month DayofWeek
Соответствующее значение, диапазон значений домена и специальный индикатор каждого поля слева направо:
поле | разрешение | разрешенные специальные символы |
---|---|---|
второй | 0-59 | , - * / |
Минута | 0-59 | , - * / |
Час | 0-23 | , - * / |
Дата | 1-31 | , - * / L W C |
месяц | 1-12 или ЯНВАРЬ-ДЕКАБРЬ | , - * / |
Неделю | 1-7 или вс-сб | , - * / L C # |
год (необязательно) | Оставьте пустым, 1970-2099 гг. | , - * / |
Как показывает приведенное выше выражение:
-
""персонаж:используется для указания всех значений. Например, «каждую минуту» представлено в поле минут.
-
"-"персонаж:используется для указания диапазона. Например: «10-12» означает «10 часов, 11 часов, 12 часов» в поле часов.
-
","персонаж:используется для указания дополнительных значений. Например: «ПН,СР,ПТ» означает «понедельник, среда, пятница» в поле недели.
-
"?"персонаж:Используется только в полях даты и недели. Он используется для указания «неявных значений». Это полезно, когда вам нужно указать что-то через одно из этих двух полей. Посмотрите на пример ниже, и вы все поймете.
-
символ "Л":Укажите день (последний день) месяца или недели. Сокращение от «Последний». Но «L» означает разные значения в неделе и месяце, например: «L» в подразделе месяца относится к последнему дню месяца - 31 января, 28 февраля.
- Он просто представлен как «7» или символ «SAT», если он находится в поле дня недели.
- Если он стоит после значения в поле недели, это означает «значение последней недели месяца», например, «6L» означает последнюю пятницу месяца.
-
Символ «В»:Может использоваться только в поле месяца, которое указывает ближайшее к указанной дате воскресенье.
-
"#"персонаж:Может использоваться только в поле недели, которое указывает количество недель в месяце.
Каждый элемент может явно указывать значение (например,6
), интервал (например,9-12
), список (например,9,11,13
) или подстановочный знак (например,*
)."день месяца"и"день недели"Эти два элементавзаимоисключающий, поэтому это следует сделать, установиввопросительный знак(?
), чтобы указать, какое поле вы не хотите устанавливать. В таблице ниже показаны некоторыеcron
выразительныйпримери их значение:
выражение | значение |
---|---|
"0 0 12 * * ?" | Запуск каждый день в 12:00 |
"0 15 10 ? * *" | Запуск каждый день в 10:15 |
"0 15 10 * * ?" | Запуск каждый день в 10:15 |
"0 15 10 * * ? *" | Запуск каждый день в 10:15 |
"0 15 10 * * ? 2005" | Выстрел в 10:15 каждый день в 2005 году. |
"0 * 14 * * ?" | Срабатывает каждую минуту с 14:00 до 14:59 каждый день |
"0 0/5 14 * * ?" | Срабатывает каждые 5 минут с 14:00 до 14:55 каждый день |
"0 0/5 14,18 * * ?" | Срабатывает каждые 5 минут с 14:00 до 14:55 и каждые 5 минут с 18:00 до 18:55. |
"0 0-5 14 * * ?" | Срабатывает каждую минуту с 14:00 до 14:05 каждый день |
"0 10,44 14 ? 3 WED" | Каждую среду марта в 14:10 и 14:44. |
"0 15 10 ? * MON-FRI" | Запускается в 10:15 с понедельника по пятницу |
"0 15 10 15 * ?" | Запускается в 10:15 утра 15-го числа каждого месяца |
"0 15 10 L * ?" | Запускается в 10:15 в последний день месяца |
"0 15 10 ? * 6L" | Загорается в последнюю пятницу месяца в 10:15. |
"0 15 10 ? * 6L 2002-2005" | Выстрел в 10:15 в последнюю пятницу каждого месяца с 2002 по 2005 год. |
"0 15 10 ? * 6#3" | Срабатывает в 10:15 в третью пятницу месяца. |
0 6 * * * | каждое утро в 6 утра |
0 /2 * * | каждые два часа |
0 23-7/2, 8 * * * | Каждые два часа с 23:00 до 8:00, в 8:00 |
0 11 4 * 1-3 | 4 числа каждого месяца и каждый понедельник-среда в 11:00 |
0 4 1 1 * | 1 января в 4 утра |
Подготовка окружающей среды
Настройка зависимостей градиента
использоватьSpring Initializer
Создаватьgradle
проектspring-boot-scheduler-task-management
, добавляйте связанные зависимости при создании. получить начальныйbuild.gradle
следующее:
buildscript {
ext {
springBootVersion = '2.0.3.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'io.ostenant.springboot.sample'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
существуетSpring Boot
Конфигурация начального класса@EnableScheduling
Аннотация включенаSpring
Встроенная функция обработки времени.
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Настройка задач таймера
этоAPI
В настоящее время он редко используется в проекте, а пример кода приводится напрямую. Подробное введение см.API
.Timer
только внутринить,Если естьнесколько задачтогда это будетПоследовательное исполнение, такая задачазадерживатьивремя обращенияПроблемы возникнут.
TimerService.java
public class TimerService {
private static final Logger LOGGER = LoggerFactory.getLogger(TimerService.class);
private AtomicLong counter = new AtomicLong();
public void schedule() {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
long count = counter.incrementAndGet();
LOGGER.info("Schedule timerTask {} times", count);
}
};
Timer timer = new Timer();
timer.schedule(timerTask, 1000L, 10 * 1000L;
}
}
Приведенный выше код определяетTimerTask
,существуетTimerTask
Накопитьколичество казней, и пройтиslf4j
Печать (со своим временем выполнения). затем пройтиTimer
инструмент планированияTimerTask
задачи, настройкиВремя задержки инициализацииза1s
,Интервал выполнения по времениза10s
, тестовый код выглядит следующим образом:
public static void main(String[] args) {
TimerService timerService = new TimerService();
timerService.schedule();
}
Глядя на результаты теста, вы можете найтиTimerTask
Настроенные задачи каждые10s
Выполняется один раз, поток выполнения по умолчаниюTimer-0
эта нить.
17:48:18.731 [Timer-0] INFO io.ostenant.springboot.sample.timer.TimerService - Schedule timerTask 1 times
17:48:28.730 [Timer-0] INFO io.ostenant.springboot.sample.timer.TimerService - Schedule timerTask 2 times
17:48:38.736 [Timer-0] INFO io.ostenant.springboot.sample.timer.TimerService - Schedule timerTask 3 times
17:48:48.738 [Timer-0] INFO io.ostenant.springboot.sample.timer.TimerService - Schedule timerTask 4 times
17:48:58.743 [Timer-0] INFO io.ostenant.springboot.sample.timer.TimerService - Schedule timerTask 5 times
Настройка задачи ScheduledExecutorService
ScheduledExecutorService
даОтложенное выполнениепул потоков дляМногопоточностьокружающая обстановказадача на время, рекомендуется использоватьScheduledExecutorService
заменятьTimer
таймер.
Создайте тему с количеством4
изпул потоков задач, в то же время и совершить его4
Временная задача для тестирования отложенных задачПараллельная обработка. воплощать в жизньScheduledExecutorService
изscheduleWithFixedDelay()
метод установки пула потоков задачНачальное время задержки задачиза2
секунды, и последний размомент времени исполненияпосле10
секунд до выполнения следующей задачи.
public void scheduleWithFixedDelay() {
ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(4);
for (int i = 0; i < 4; i++) {
scheduledExecutor.scheduleWithFixedDelay(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10 * 1000L);
} catch (InterruptedException e) {
LOGGER.error("Interrupted exception", e);
}
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times with fixed delay", count);
}, 2000L, 10 * 1000L, TimeUnit.MILLISECONDS);
}
LOGGER.info("Start to schedule");
}
Результаты теста следующие, мы можем обнаружить, что каждый20
интервал секунд, будет4
Запланированные задачи выполняются одновременно. Потому что, когда пул потоков задач инициализируется, мы одновременно отправляемся в пул потоков4
задача, эточетыре задачибудет полностью использовать пул потоков4
потоки для выполнения задач.
20
Как появились секунды? первая из каждой задачивременной интервалУстановить как10
второй. Во-вторых, потому чтоwithFixedDelay
стратегия, то есть то, что выполняет текущая задачаВремя окончания, в качестве следующей задачи задержкизапустить узел синхронизации, и каждая задача приостанавливается во время выполнения10
секунд, общее время равно20
секунды.
19:42:02.444 [main] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Start to schedule
19:42:14.449 [pool-1-thread-1] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 3 times with fixed delay
19:42:14.449 [pool-1-thread-2] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 1 times with fixed delay
19:42:14.449 [pool-1-thread-3] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 2 times with fixed delay
19:42:14.449 [pool-1-thread-4] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 4 times with fixed delay
19:42:34.458 [pool-1-thread-4] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 7 times with fixed delay
19:42:34.458 [pool-1-thread-3] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 5 times with fixed delay
19:42:34.458 [pool-1-thread-2] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 8 times with fixed delay
19:42:34.458 [pool-1-thread-1] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 6 times with fixed delay
Создайте тему с количеством4
изпул потоков задач, в то же время и совершить его4
Временная задача для тестирования отложенных задачПараллельная обработка. Выполняйте каждую задачу отдельноScheduledExecutorService
изscheduleAtFixedRate()
метод установки пула потоков задачНачальное время задержки задачиза2
секунды, и последний развремя начала выполненияпосле10
секунд до выполнения следующей задачи.
public void scheduleAtFixedRate() {
ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(4);
for (int i = 0; i < 4; i++) {
scheduledExecutor.scheduleAtFixedRate(() -> {
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times at fixed rate", count);
}, 2000L, 10 * 1000L, TimeUnit.MILLISECONDS);
}
LOGGER.info("Start to schedule");
}
Результаты теста следующие, мы можем обнаружить, что каждый10
интервал секунд, будет4
Каждая синхронизированная задача выполняется в одно и то же время, поскольку при инициализации пула потоков задач мы отправляемся в пул потоков одновременно.4
задача, эточетыре задачибудет полностью использовать пул потоков4
потоки для выполнения задач.
19:31:46.837 [main] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Start to schedule
19:31:48.840 [pool-1-thread-1] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 1 times at fixed rate
19:31:48.840 [pool-1-thread-3] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 3 times at fixed rate
19:31:48.840 [pool-1-thread-2] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 2 times at fixed rate
19:31:48.840 [pool-1-thread-4] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 4 times at fixed rate
19:31:58.839 [pool-1-thread-2] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 6 times at fixed rate
19:31:58.840 [pool-1-thread-4] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 8 times at fixed rate
19:31:58.839 [pool-1-thread-3] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 7 times at fixed rate
19:31:58.839 [pool-1-thread-1] INFO io.ostenant.springboot.sample.executor.ScheduledExecutorsService - Schedule executor 5 times at fixed rate
Настройка задач Spring Task
Spring
при условии@Scheduled
Аннотация для достижениязадача на время,@Scheduled
параметры приемлемыдваНастройки синхронизации, один обычно используетсяВыражение зеленого времени cron = "*/10 * * * * *"
, другойfixedRate = 10 * 1000L
, оба представляют каждый10
Выполнять целевую задачу раз в секунду.
Описание параметра:
- @Scheduled(fixedRate = 10 * 1000L): последний развремя начала выполненияпосле
10
Выполнить снова в секундах.
@Scheduled(fixedRate = 10 * 1000L)
public void scheduleAtFixedRate() throws Exception {
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times at fixed rate", count);
}
- @Scheduled(fixedDelay = 10 * 1000L): последний размомент времени выполненияпосле
10
Выполнить снова в секундах.
@Scheduled(fixedDelay = 10 * 1000L)
public void scheduleWithFixedDelay() throws Exception {
try {
TimeUnit.MILLISECONDS.sleep(10 * 1000L);
} catch (InterruptedException e) {
LOGGER.error("Interrupted exception", e);
}
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times with fixed delay", count);
}
- @Scheduled(initialDelay = 2000L, fixedRate = 10 * 1000L): первая задержка
2
Выполните в секундах, затем нажмитеfixedRate
правила за10
Выполнять раз в секунду.
@Scheduled(initialDelay = 2000L, fixedDelay = 10 * 1000L)
public void scheduleWithinitialDelayAndFixedDelay() throws Exception {
try {
TimeUnit.MILLISECONDS.sleep(10 * 1000L);
} catch (InterruptedException e) {
LOGGER.error("Interrupted exception", e);
}
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times with fixed delay", count);
}
- @Scheduled(cron = "0/10 * * * * *"): согласно
cron
определение выражения, любое другое10
Выполнять раз в секунду.
@Scheduled(cron = "0/10 * * * * *")
public void scheduleWithCronExpression() throws Exception {
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times with ", count);
}
Полный код выглядит следующим образом:
SpringTaskService.java
@Component
public class SpringTaskService {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringTaskService.class);
private AtomicLong counter = new AtomicLong();
@Scheduled(fixedDelay = 10 * 1000L)
public void scheduleWithFixedDelay() throws Exception {
try {
TimeUnit.MILLISECONDS.sleep(10 * 1000L);
} catch (InterruptedException e) {
LOGGER.error("Interrupted exception", e);
}
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times with fixed delay", count);
}
@Scheduled(initialDelay = 2000L, fixedDelay = 10 * 1000L)
public void scheduleWithinitialDelayAndFixedDelay() throws Exception {
try {
TimeUnit.MILLISECONDS.sleep(10 * 1000L);
} catch (InterruptedException e) {
LOGGER.error("Interrupted exception", e);
}
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times with fixed delay", count);
}
@Scheduled(fixedRate = 10 * 1000L)
public void scheduleAtFixedRate() throws Exception {
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times at fixed rate", count);
}
@Scheduled(cron = "0/10 * * * * *")
public void scheduleWithCronExpression() throws Exception {
long count = counter.incrementAndGet();
LOGGER.info("Schedule executor {} times with ", count);
}
}
Просмотр журнала, задача каждые20
Выполняется один раз с интервалом в несколько секунд. Каждый раз, когда запланированная задача находится в последнеммомент времени выполненияпосле10
Секунды на повторное выполнение, заданные в задачевремя спатьза10
второй. Здесь проверяется только @Scheduled(initialDelay = 2000L, fixedDelay = 10 * 1000L).
2018-06-25 18:00:53.051 INFO 5190 --- [pool-1-thread-1] i.o.s.sample.spring.SpringTaskService : Schedule executor 1 times with fixed delay
2018-06-25 18:01:13.056 INFO 5190 --- [pool-1-thread-1] i.o.s.sample.spring.SpringTaskService : Schedule executor 2 times with fixed delay
2018-06-25 18:01:33.061 INFO 5190 --- [pool-1-thread-1] i.o.s.sample.spring.SpringTaskService : Schedule executor 3 times with fixed delay
2018-06-25 18:01:53.071 INFO 5190 --- [pool-1-thread-1] i.o.s.sample.spring.SpringTaskService : Schedule executor 4 times with fixed delay
2018-06-25 18:02:13.079 INFO 5190 --- [pool-1-thread-1] i.o.s.sample.spring.SpringTaskService : Schedule executor 5 times with fixed delay
Настройка пула потоков задач
Вышеупомянутая конфигурация основана наодин потокпланирование задач, как ввестиМногопоточностьулучшатьЗадержка задачиизПараллельная обработкаспособность?
Spring Boot
предоставилSchedulingConfigurer
Настройте интерфейс. мы проходимScheduleConfig
Реализация конфигурационного файлаScheduleConfiguration
интерфейс и переопределитьconfigureTasks()
метод, чтобыScheduledTaskRegistrar
ЗарегистрироватьThreadPoolTaskScheduler
объект потока задач.
@Configuration
public class ScheduleConfiguration implements SchedulingConfigurer {
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleConfiguration.class);
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setTaskScheduler(taskScheduler());
}
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(4);
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setThreadNamePrefix("schedule");
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setErrorHandler(t -> LOGGER.error("Error occurs", t));
return taskScheduler;
}
}
запускатьSpring Boot
цитата вышеSpringTaskService
настроен4
Каждая запланированная задача вступит в силу в одно и то же время.
2018-06-20 20:37:50.746 INFO 8142 --- [ schedule1] i.o.s.sample.spring.SpringTaskService : Schedule executor 1 times at fixed rate
2018-06-20 20:38:00.001 INFO 8142 --- [ schedule3] i.o.s.sample.spring.SpringTaskService : Schedule executor 2 times with
2018-06-20 20:38:00.751 INFO 8142 --- [ schedule1] i.o.s.sample.spring.SpringTaskService : Schedule executor 3 times at fixed rate
2018-06-20 20:38:02.748 INFO 8142 --- [ schedule2] i.o.s.sample.spring.SpringTaskService : Schedule executor 4 times with fixed delay
2018-06-20 20:38:10.005 INFO 8142 --- [ schedule4] i.o.s.sample.spring.SpringTaskService : Schedule executor 5 times with
2018-06-20 20:38:10.747 INFO 8142 --- [ schedule3] i.o.s.sample.spring.SpringTaskService : Schedule executor 6 times at fixed rate
2018-06-20 20:38:20.002 INFO 8142 --- [ schedule2] i.o.s.sample.spring.SpringTaskService : Schedule executor 7 times with
2018-06-20 20:38:20.747 INFO 8142 --- [ schedule4] i.o.s.sample.spring.SpringTaskService : Schedule executor 8 times at fixed rate
журнал просмотра,префикс имени темызаschedule
, его можно найтиSpring Task
будет@Scheduled
Аннотированный настроен4
задачи, распределенные по нашим настроеннымThreadPoolTaskScheduler
середина4
Потоки выполняются одновременно.
резюме
В этом документе представлены планирование и реализация задач синхронизации на основе одного узла, включаяJDK
оригинальныйTimer
иScheduledExecutorService
,а такжеSpring 3.0
на основе аннотацийSpring Task
планирование задач. Кроме того, акцент делается наФиксированная задержка,фиксированная частотаиcron
выражениеразница, иScheduledExecutorService
иSpring Scheduler
изПараллельная обработка пула потоковпрохождение теста.
Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack
Эта учетная запись будет продолжать делиться сухими товарами серверных технологий, включая основы виртуальных машин, многопоточное программирование, высокопроизводительные фреймворки, асинхронное ПО, промежуточное ПО для кэширования и обмена сообщениями, распределенные и микросервисы, материалы для обучения архитектуре и расширенные учебные материалы и статьи.