Я долго писал вопрос и долго. Но я старался показать как можно больше того, что я сделал, а что не ясно. Пожалуйста, закончите чтение и спасибо за ваше терпение!
Я перепробовал много экспериментов, напиши spring doc spring doc , (напиши вопросы на этом сайте) Но все равно не понимаю полную картину.
У меня есть задача реализовать несколько планировщиков на одном сервере весенней загрузки.
- Первый планировщик будет проверять данные в БД каждую 1 секунду и запускать некоторую логику.
- Второй планировщик будет отправлять запросы сторонним службам каждые 10 миллисекунд.
Южные планировщики должны работать с пулом потоков и иметь разные настройки. Например первый - 5 потоков, второй - 10 потоков. Хотя я понял, я попробовал несколько вариантов и, наконец, запутался, что выбрать и как правильно его использовать:
Для теста я создаю 2 компонента с логикой и каждый раз буду вызывать методы из этого компонента:
@Slf4j
@Component
public class TestBean {
public void test(){
try {
Thread.sleep(9000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("First bean print");
}
}
и
@Slf4j
@Component
public class TestBean2 {
public void test(){
try {
Thread.sleep(9000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("Second bean print");
}
}
Я до сих пор не понимаю разницы, что и когда использовать - @Scheduled
аннотация или TaskScheduler
из кода. Я пытался создать метод с @Scheduled
аннотацией:
@Slf4j
@Component
public class MyScheduler {
private final TestBean testBean;
private final TestBean2 testBean2;
public MyScheduler(TestBean testBean, TestBean2 testBean2) {
this.testBean = testBean;
this.testBean2 = testBean2;
}
@Scheduled(fixedRate = 1000L)
public void test() {
testBean.test();//call method from first bean every 1 sec
}
}
Выходной журнал:
2018-09-05 13:17:28.799 INFO 10144 --- [pool-1-thread-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:17:37.799 INFO 10144 --- [pool-1-thread-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:17:46.799 INFO 10144 --- [pool-1-thread-1] com.example.scheduling.TestBean : First bean print
Обрабатывать одну нить и печатать журнал из первого компонента 9 с . После этого я добавляю TaskScheduler
:
@Bean
ThreadPoolTaskScheduler taskScheduler(){
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
threadPoolTaskScheduler.setThreadNamePrefix("TASK_SCHEDULER_FIRST-");
return threadPoolTaskScheduler;
}
И запустите приложение. Выход:
2018-09-05 13:21:40.973 INFO 7172 --- [HEDULER_FIRST-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:21:49.973 INFO 7172 --- [HEDULER_FIRST-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:21:58.973 INFO 7172 --- [HEDULER_FIRST-2] com.example.scheduling.TestBean : First bean print
2018-09-05 13:22:07.973 INFO 7172 --- [HEDULER_FIRST-1] com.example.scheduling.TestBean : First bean print
Каждый 9 сек , но разные потоки печатают журнал из первого компонента.
После этого я пытаюсь ввести TaskScheduler
и запустить расписание другим способом:
@Slf4j
@Component
public class MyScheduler {
private final TestBean testBean;
private final TestBean2 testBean2;
private final ThreadPoolTaskScheduler taskScheduler;
public MyScheduler(TestBean testBean, TestBean2 testBean2, ThreadPoolTaskScheduler taskScheduler) {
this.testBean = testBean;
this.testBean2 = testBean2;
this.taskScheduler = taskScheduler;
}
@PostConstruct
public void test() {
taskScheduler.scheduleAtFixedRate(testBean::test, 1000L);
testBean.test();
}
}
Но получил похожий вывод:
2018-09-05 13:25:54.541 INFO 7044 --- [HEDULER_FIRST-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:26:03.541 INFO 7044 --- [HEDULER_FIRST-2] com.example.scheduling.TestBean : First bean print
2018-09-05 13:26:12.541 INFO 7044 --- [HEDULER_FIRST-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:26:21.541 INFO 7044 --- [HEDULER_FIRST-3] com.example.scheduling.TestBean : First bean print
После этого я прочитал, что мне нужно использовать аннотацию @Async
и запустить метод bean в async:
@Slf4j
@Component
public class TestBean {
@Async
public void test(){
try {
Thread.sleep(9000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("First bean print");
}
}
Выход:
2018-09-05 13:28:07.868 INFO 8608 --- [HEDULER_FIRST-2] com.example.scheduling.TestBean : First bean print
2018-09-05 13:28:07.868 INFO 8608 --- [HEDULER_FIRST-3] com.example.scheduling.TestBean : First bean print
2018-09-05 13:28:08.860 INFO 8608 --- [HEDULER_FIRST-4] com.example.scheduling.TestBean : First bean print
2018-09-05 13:28:09.860 INFO 8608 --- [HEDULER_FIRST-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:28:10.860 INFO 8608 --- [HEDULER_FIRST-5] com.example.scheduling.TestBean : First bean print
Каждые 1 сек начать новую тему. Это оно! Но что, если я верну @Scheduled
аннотацию:
@Scheduled(fixedRate = 1000L)
public void test() {
testBean.test();//async method
}
Результат такой же, как и в предыдущей версии. именно то, что нужно!
Но теперь я хочу использовать второй компонент. Я превращаю метод во второй компонент Async и пытаюсь запустить:
@Scheduled(fixedRate = 1000L)
public void test() {
testBean.test();
testBean2.test();
}
Выход:
2018-09-05 13:32:46.079 INFO 11108 --- [HEDULER_FIRST-1] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:32:46.079 INFO 11108 --- [HEDULER_FIRST-2] com.example.scheduling.TestBean : First bean print
2018-09-05 13:32:47.074 INFO 11108 --- [HEDULER_FIRST-3] com.example.scheduling.TestBean : First bean print
2018-09-05 13:32:47.074 INFO 11108 --- [HEDULER_FIRST-4] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:32:48.074 INFO 11108 --- [HEDULER_FIRST-5] com.example.scheduling.TestBean : First bean print
Оба метода используют ОДИН ThreadPoolTaskScheduler
с 5 потоками. Но мне нужно начинать каждый метод с разных ThreadPoolTaskScheduler
. Я создаю второй ThreadPoolTaskScheduler
:
@Bean
ThreadPoolTaskScheduler taskScheduler2(){
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(9);
threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
threadPoolTaskScheduler.setThreadNamePrefix("TASK_SCHEDULER_SECOND-");
return threadPoolTaskScheduler;
}
И начать:
2018-09-05 13:35:31.152 INFO 14544 --- [ main] c.e.scheduling.SchedulingApplication : Started SchedulingApplication in 1.669 seconds (JVM running for 2.141)
2018-09-05 13:35:40.134 INFO 14544 --- [cTaskExecutor-2] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:35:40.134 INFO 14544 --- [cTaskExecutor-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:35:41.127 INFO 14544 --- [cTaskExecutor-4] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:35:41.127 INFO 14544 --- [cTaskExecutor-3] com.example.scheduling.TestBean : First bean print
2018-09-05 13:35:42.127 INFO 14544 --- [cTaskExecutor-5] com.example.scheduling.TestBean : First bean print
2018-09-05 13:35:42.127 INFO 14544 --- [cTaskExecutor-6] com.example.scheduling.TestBean2 : Second bean print
Обе бины печатают журнал, но с cTaskExecutor
и не используют tasckScheduler1
или tasckScheduler2
Это мой первый вопрос - почему? Как это может работать?
Теперь я попытался использовать эту реализацию:
@Slf4j
@Component
public class MyScheduler {
private final TestBean testBean;
private final TestBean2 testBean2;
private final ThreadPoolTaskScheduler poolTaskScheduler1;
private final ThreadPoolTaskScheduler poolTaskScheduler2;
public MyScheduler(TestBean testBean, TestBean2 testBean2,
@Qualifier("first") ThreadPoolTaskScheduler poolTaskScheduler1,
@Qualifier("second") ThreadPoolTaskScheduler poolTaskScheduler2) {
this.testBean = testBean;
this.testBean2 = testBean2;
this.poolTaskScheduler1 = poolTaskScheduler1;
this.poolTaskScheduler2 = poolTaskScheduler2;
}
// @Scheduled(fixedRate = 1000L)
@PostConstruct
public void test() {
poolTaskScheduler1.scheduleAtFixedRate(testBean::test, 1000L);
poolTaskScheduler2.scheduleAtFixedRate(testBean2::test, 1000L);
}
}
Вывод: ничего не изменилось.
И В готово я возвращаю код:
@Scheduled(fixedRate = 1000L)
public void test() {
testBean.test();
testBean2.test();
}
И использовать @Async
с квалификатором:
@Async("first")
@Async("second")
Выход:
2018-09-05 13:44:11.489 INFO 7432 --- [EDULER_SECOND-1] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:44:11.489 INFO 7432 --- [HEDULER_FIRST-1] com.example.scheduling.TestBean : First bean print
2018-09-05 13:44:12.484 INFO 7432 --- [EDULER_SECOND-2] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:44:12.484 INFO 7432 --- [HEDULER_FIRST-2] com.example.scheduling.TestBean : First bean print
2018-09-05 13:44:13.484 INFO 7432 --- [HEDULER_FIRST-3] com.example.scheduling.TestBean : First bean print
2018-09-05 13:44:13.484 INFO 7432 --- [EDULER_SECOND-3] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:44:14.484 INFO 7432 --- [EDULER_SECOND-4] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:44:14.484 INFO 7432 --- [HEDULER_FIRST-4] com.example.scheduling.TestBean : First bean print
2018-09-05 13:44:15.484 INFO 7432 --- [EDULER_SECOND-5] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:44:15.484 INFO 7432 --- [HEDULER_FIRST-5] com.example.scheduling.TestBean : First bean print
2018-09-05 13:44:16.483 INFO 7432 --- [EDULER_SECOND-6] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:44:17.483 INFO 7432 --- [EDULER_SECOND-7] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:44:18.483 INFO 7432 --- [EDULER_SECOND-8] com.example.scheduling.TestBean2 : Second bean print
2018-09-05 13:44:19.483 INFO 7432 --- [EDULER_SECOND-9] com.example.scheduling.TestBean2 : Second bean print
именно то, что нужно! Но я не понимаю, правильно ли я поступаю
Если я изменю ThreadPoolTaskScheduler
на ThreadPoolTaskExecutor
, все будет работать так же. Так что я должен использовать?
ThreadPoolTaskScheduler
или ThreadPoolTaskExecutor
@Scheduled
или ThreadPoolTaskScheduler
/ ThreadPoolTaskExecutor
из кода?
@Scheduled
с ThreadPoolTaskScheduler
/ ThreadPoolTaskExecutor
из кода или @Async
?