Расширенное использование запланированных задач Spring
предыдущий пост в блоге«Основное использование задач синхронизации Spring»Представлено простое использование временных задач в среде Spring и оставлено несколько вопросов, на которые мы надеемся дать ответы в этой статье.
I. обычные задачи Расширенные статьи
1. Краткое описание проблемы
В предыдущем сообщении в блоге были заданы следующие вопросы, а затем проанализированы проблемы.
- Когда в проекте несколько запланированных задач, они выполняются параллельно или последовательно?
- Если по умолчанию серийный
- Итак, существует ли последовательность между временными задачами с одним и тем же выражением crond?
- Влияет ли блокировка задачи на последующие задачи?
- Что, если вам нужно, чтобы они выполняли параллельно?
- Если выполняется одновременно
- Это создать новый поток или использовать пул потоков для его повторного использования?
- При параллельном выполнении предположим, что есть задача, которая выполняется один раз в секунду, но когда для однократного выполнения требуется более 1 с, какова производительность этой задачи? Вы продолжаете добавлять новые потоки для выполнения или ждете завершения выполнения перед выполнением следующего?
2. Последовательно-параллельный анализ нескольких задач синхронизации
Как проверить, выполняются ли несколько запланированных задач в проекте последовательно или одновременно? Чтобы проверить эту функцию, лучше всего написать тестовый пример, например, определить две временные задачи и написать бесконечный цикл в одной из задач, чтобы увидеть, будет ли нормально выполняться другая задача.
@Scheduled(cron = "0/1 * * * * ?")
public void sc1() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
while (true) {
Thread.sleep(5000);
}
}
@Scheduled(cron = "0/1 * * * * ?")
public void sc2() {
System.out.println(Thread.currentThread().getName() + " | sc2 " + System.currentTimeMillis());
}
Прежде всего, мы анализируем ли выполнение двух задач SC1 и SC2 серийный или параллель. В настоящее время мы не будем рассмотреть возможность блокировки, когда SC1 называется, и следует ли следующую секунду, чтобы открыть новую нить, а затем Вызов SC1.
- Если сериал: напечатанный как только SC1, SC2 может распечатать 0 или 1 раз
- Если параллельно: sc1 печатает один раз, sc2 печатает n раз
Фактическая работа, диаграмма GIF демонстрируется следующим образом.
Результаты на приведенном выше рисунке подтверждают, что по умолчанию несколько запланированных задач выполняются последовательно; если одна задача заблокирована, это повлияет на другие задачи.
3. Приоритет выполнения запланированной задачи
Поскольку он выполняется последовательно, как определяется приоритет? Это фиксируется каждый раз, или это случайно?
Вышеприведенный метод также легко проверить.Для тех же двух задач посмотрите, не будет ли их вывод перепутан.Если задача 1 печатается, а затем задача 2 печатается каждый раз, это фиксированный приоритет; в противном случае, каждый раз, когда запланировано, порядок трудно сказать
Код теста выглядит следующим образом
@Scheduled(cron = "0/1 * * * * ?")
public void sc1() {
System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
}
@Scheduled(cron = "0/1 * * * * ?")
public void sc2() {
System.out.println(Thread.currentThread().getName() + " | sc2 " + System.currentTimeMillis());
}
Результаты измерений следующие
Вывод из вывода: заказ растянут и не показывает явной приоритетной связи
4. Параллельное планирование
Следующий вопрос заключается в том, что я хочу, чтобы эти задачи выполнялись одновременно, возможно ли это?
Конечно, это возможно, и это относительно просто использовать.Первый — добавить аннотации в приложение.@EnableAsync
, откройте асинхронный вызов, а затем добавьте его в запланированную задачу.@Async
Просто аннотируйте, простая демонстрация выглядит следующим образом
@EnableAsync
@EnableScheduling
@SpringBootApplication
public class QuickMediaApplication {
public static void main(String[] args) {
SpringApplication.run(QuickMediaApplication.class, args);
}
@Scheduled(cron = "0/1 * * * * ?")
@Async
public void sc1() {
System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
}
}
После выполнения вышеуказанного проверьте вывод (теоретически имя потока должно быть другим при асинхронном планировании)
Из приведенного выше вывода можно просто сделать вывод, что каждый раз, когда запланирована вышеуказанная задача, для ее выполнения открывается новый поток, поэтому, если в задании по времени записан бесконечный цикл, приведет ли он к бесконечным потокам и, наконец, ко всему процесс рухнул?
Кроме того, количество потоков одного процесса в системе Linux находится в режиме онлайн.Команда проверки:
ulimit -u
Перед тестированием посмотрите на обычное выполнение задачи выше, как показано на анимации ниже, количество потоков не преувеличено.
Затем переключитесь на метод планирования бесконечного цикла.Фактический тест выглядит следующим образом, и количество потоков увеличивается
Поэтому не рекомендуется использовать метод асинхронного вызова по умолчанию.Возможно, вас убьют, и вы не узнаете об этом.Можете ли вы использовать свой собственный пул потоков для управления этими асинхронными задачами?
Пользовательский пул резьбы
Замена метода управления потоками по умолчанию на собственный пул потоков, несомненно, является более безопасным и гибким методом, и его использование не вызывает затруднений. Он ничем не отличается от процедуры создания пула потоков. Чтобы использовать его в экосистеме Spring, просто использовать его Превратить в боб
Непосредственно с помощью пула потоков SpringThreadPoolTaskExecutor
@Bean
public AsyncTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("yhh-schedule-");
executor.setMaxPoolSize(10);
executor.setCorePoolSize(3);
executor.setQueueCapacity(0);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
return executor;
}
@Scheduled(cron = "0/1 * * * * ?")
@Async
public void sc1() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
while (true) {
Thread.sleep(1000 * 5);
}
}
Результаты фактической демонстрации следующие: максимум 10 потоков, а повторно отправленные задачи напрямую отбрасываются.
Вкратце, преимущества использования пользовательского пула потоков:
- Разумное распределение параметров пула потоков
- Интересен и выбор стратегии отбраковки (вы можете обрабатывать «нагрузочные» задачи по своим представлениям)
- Имя пула потоков будет очень полезно для устранения неполадок в будущем.
6. Резюме
Первоначально этот пост в блоге должен был быть написан вчера, 2 августа, но в производственной среде ночью, за исключением некоторых проблем, было относительно поздно после устранения онлайн-сбоя, и это было оставлено на сегодня.Эй, прокрастинация тоже неприемлемо. . .
Ниже приведены некоторые сведения о задачах синхронизации в Spring.
- По умолчанию все задачи синхронизации планируются последовательно, в один поток, и даже если порядок двух задач с одним и тем же крондом не гарантируется (конкретная причина требует анализа исходного кода, посмотрите, как это поддерживается)
- использовать
@Async
Аннотации могут сделать запланированные задачи асинхронно запланированными, но вам нужно открыть конфигурацию и добавить ее в класс запуска.@EnableAsync
аннотация - При включении одновременного выполнения рекомендуется использовать собственный пул потоков вместо пула по умолчанию, причины см. выше.
II. Другое
0. Актуально
1. Серый блог: https://juneb.GitHub.IO/hex блог
Серый личный блог, записывающий все посты блога по учебе и работе, приглашаю всех в гости
2. Заявление
Это не так хорошо, как письмо веры.Контент уже написан, и это чисто из семьи.Из-за ограниченных личных возможностей неизбежно будут упущения и ошибки.Если вы найдете ошибки или лучше предложения, вы можете критиковать и исправлять их. Спасибо
- Адрес вейбо:Блог Маленького Серого
- QQ: серо-серый / 3302797840
3. Сканируйте внимание
Блог Little Grey и общедоступный номер
планета знаний