我写了很久很久的问题了。但是我试图尽可能多地展示我所做的事情和不清楚的事情。请完成阅读并感谢您的耐心!
我尝试了许多实验,写了spring doc spring doc,(在此站点中写了问题),但仍然不了解全部内容。
我的任务是在一台spring-boot服务器中实现一些调度程序。
South调度程序必须与线程池一起使用,并具有不同的设置。例如,前5个线程,后10个线程。据我所知,我尝试了几种选择,最后感到困惑,我应该选择什么以及如何更正确地使用它:
为了进行测试,我创建了两个具有逻辑的bean,每次都会从该bean中调用方法:
@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秒从第一个bean打印日志。之后,我添加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秒,但是不同的线程从第一个bean打印日志。
之后,我尝试注入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的方法:
@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
}
结果与以前的版本相同。到底需要什么!
但是现在我要使用第二个bean。我也将方法放入第二个bean 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
两种方法都使用一个带有5个线程的ThreadPoolTaskScheduler
。但是我需要以不同的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
两个bean都打印日志,但是带有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
?
答案 0 :(得分:1)
让我们一一解答您的问题:
您具有自定义的ThreadPoolTaskSchedulers(TaskExecutor Bean),但未正确配置@Async。默认情况下,Spring使用SimpleAsyncTaskExecutor执行您的任务。这就是为什么您只看到带有缩写线程名[cTaskExecutor-1],[cTaskExecutor-2]等的日志的原因。 如果要使用taskScheduler1或taskScheduler2,则必须使用相应的名称配置@Async。
@Async("taskScheduler1")
public void test(){
try {
Thread.sleep(9000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("First bean print");
}
稍后,您为Bean配置了执行器名称“ first”和“ second”,因此您的异步任务有效。 @Async查找并找到具有提供的名称的执行者Bean。
TaskScheduler设计用于计划任务,而TaskExecutor设计用于异步任务。 ThreadPoolTaskScheduler实现TaskScheduler和TaskExecutor。 ThreadPoolTaskExecutor实现TaskExecutor,而不是TaskScheduler。
您正在使用调度任务来触发异步任务,因此ThreadPoolTaskScheduler和 ThreadPoolTaskExecutor可以互换,除非您想使用 ThreadPoolTaskExecutor在线程池上的细粒度配置,例如 setCorePoolSize , setMaxPoolSize ,..如果您使用多个调度任务,则需要 实现ThreadPoolTaskScheduler,因为默认情况下所有@Scheduled任务都是 在Spring创建的大小为1的默认线程池中执行。