описание проблемы
Каждый должен использовать временные задачи Springboot, добавить две аннотации и добавить некоторую конфигурацию для запуска. Но если это только на уровне приложения, есть много присущих проблем, которые может быть трудно обнаружить в процессе разработки. Без дальнейших церемоний, я буду использоватькрайнее преувеличениеметод, опишите возникшую проблему.
@Component
public class ScheduleTest {
@Scheduled(initialDelay = 1000,fixedRate = 2*1000)
public void test_a(){
System.out.println("123");
}
@Scheduled(initialDelay = 2*1000,fixedRate = 2*1000)
public void test_b(){
while (true){
try {
Thread.sleep(2*1000);
System.out.println("456");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Приведенный выше код представляет собой две временные задачи в проекте, test_a — обычный метод, а test_b — метод, в котором возникает исключение.Чтобы выделить исключение, я создал бесконечный цикл.
В этом случае, что происходит, когда для запуска используется конфигурация задачи по времени по умолчанию? Просто попробуйте и посмотрите,Временная задача зацикливается в методе b, а метод a никогда не будет выполнен! ! !
проблема вызывает
Найден после просмотра исходного кодаАнализ исходного кода SpringBoot — принцип работы таймера по расписаниюспрингбут,Пул потоков задач по времени по умолчанию имеет только один поток., так что если есть исключение, такое как задержка или бесконечный цикл в группе задач с синхронизацией, это, вероятно, повлияет на другие задачи с синхронизацией.
решение
Поскольку проблема заключается в количестве пулов потоков, чтобы каждая задача не мешала друг другу, хорошо настроить соответствующий пул потоков.
Вариант 1 Асинхронное выполнение
@Scheduled(initialDelay = 1000,fixedRate = 2*1000)
@Async
public void test_a(){
System.out.println("123");
}
@Scheduled(initialDelay = 2*1000,fixedRate = 2*1000)
@Async
public void test_b(){
while (true){
try {
Thread.sleep(2*1000);
System.out.println("456");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Поскольку одна задача застревает в одном потоке и затрагиваются другие задачи, асинхронное выполнение этой задачи решит проблему.
Вариант 2. Настройте количество пулов потоков задач по времени.
@Configuration
public class GlobalConfiguration {
@Bean
public TaskScheduler schedule(){
return new ConcurrentTaskScheduler(new ScheduledThreadPoolExecutor(2));
}
}
Поскольку отдельные потоки могут мешать друг другу, эту проблему можно решить путем выделения достаточного количества потоков для их отдельного запуска.
Сравнение двух схем
Обе схемы могут решить проблему взаимных помех между различными задачами, но подходящую нужно выбирать в соответствии с реальной ситуацией. Давайте проанализируем код с бесконечным циклом выше.
Если бесконечный цикл все же возникает в задаче с синхронизацией, то использование асинхронного выполнения будет иметь катастрофические последствия. Потому что в потоке запланированной задачи, после выполнения каждой задачи, она будет вычислять следующий раз и добавлять другую задачу в пул асинхронных потоков. иЗадачи, добавленные в пул асинхронных потоков, занимают ресурсы потока из-за бесконечного цикла.. По мере увеличения времени все ресурсы потоков в пуле асинхронных потоков будут заняты задачами в бесконечном цикле, что приведет к блокировке всех других служб.
Лучше использовать собственный пул потоков задач по времени, потому что только когда выполнение задачи будет завершено, будет рассчитано время и будет выполнена следующая задача. Хотя задача была выполнена из-за бесконечного цикла, она также занимает ресурсы максимум одного потока, поэтому не будет иметь более широкого влияния.