在Spring定时任务@Scheduled注解使用方式浅窥这篇文章里面说起过,spring的定时任务默认是单线程的,他在某些场景下会形成堵塞,那么若是咱们想让每个任务都起一条线程去执行呢?spring
咱们可使用Spring的@Async注解十分容易的实现多线程的任务执行。
测试代码:segmentfault
@Scheduled(cron = "0/2 * * * * ?") @Async public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(6*1_000); logger.info(Thread.currentThread().getName()+"===task end"); }
结果日志多线程
2018-06-12 16:02:42.005 [taskExecutor-97] INFO service.task.testTask -taskExecutor-97===task run 2018-06-12 16:02:42.007 [taskExecutor-94] INFO service.task.testTask -taskExecutor-94===task end 2018-06-12 16:02:44.004 [taskExecutor-98] INFO service.task.testTask -taskExecutor-98===task run 2018-06-12 16:02:44.015 [taskExecutor-95] INFO service.task.testTask -taskExecutor-95===task end 2018-06-12 16:02:46.004 [taskExecutor-99] INFO service.task.testTask -taskExecutor-99===task run 2018-06-12 16:02:46.014 [taskExecutor-96] INFO service.task.testTask -taskExecutor-96===task end 2018-06-12 16:02:48.004 [taskExecutor-100] INFO service.task.testTask -taskExecutor-100===task run 2018-06-12 16:02:48.010 [taskExecutor-97] INFO service.task.testTask -taskExecutor-97===task end 2018-06-12 16:02:50.005 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task run 2018-06-12 16:02:50.008 [taskExecutor-98] INFO service.task.testTask -taskExecutor-98===task end 2018-06-12 16:02:52.006 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task run
截取部分结果日志咱们能够看到,在上一个任务6s的执行时间内,下一个任务并无等待上一个任务结束,而是在任务开始时间直接开启了一条新的线程进行执行。
仔细观察结果咱们还能够发现,每条结果都是一条新的线程,直到100时,才又从第一条线程开始。这是由于在默认不作配置的状况下,@Async所使用的线程池容量为100,每次须要的时候都会从中拿出一条,直到用完,才会等待以前的线程释放,不会再本身扩容。
下面咱们稍稍改下代码来证明一下:异步
@Scheduled(cron = "0/2 * * * * ?") @Async public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(300*1_000); logger.info(Thread.currentThread().getName()+"===task end"); }
此次我让任务执行的时间等于300s,大于100条线程总间隔时间来耗尽线程池中的线程。
结果日志测试
2018-06-12 16:26:44.411 [taskExecutor-93] INFO service.task.testTask -taskExecutor-93===task run 2018-06-12 16:26:46.853 [taskExecutor-94] INFO service.task.testTask -taskExecutor-94===task run 2018-06-12 16:26:48.008 [taskExecutor-95] INFO service.task.testTask -taskExecutor-95===task run 2018-06-12 16:26:50.008 [taskExecutor-96] INFO service.task.testTask -taskExecutor-96===task run 2018-06-12 16:26:52.006 [taskExecutor-97] INFO service.task.testTask -taskExecutor-97===task run 2018-06-12 16:26:54.008 [taskExecutor-98] INFO service.task.testTask -taskExecutor-98===task run 2018-06-12 16:26:56.006 [taskExecutor-99] INFO service.task.testTask -taskExecutor-99===task run 2018-06-12 16:26:58.005 [taskExecutor-100] INFO service.task.testTask -taskExecutor-100===task run 2018-06-12 16:28:40.142 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task end 2018-06-12 16:28:40.149 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task run 2018-06-12 16:28:42.117 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task end 2018-06-12 16:28:42.121 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task run 2018-06-12 16:28:44.253 [taskExecutor-3] INFO service.task.testTask -taskExecutor-3===task end 2018-06-12 16:28:44.257 [taskExecutor-3] INFO service.task.testTask -taskExecutor-3===task run 2018-06-12 16:28:46.027 [taskExecutor-4] INFO service.task.testTask -taskExecutor-4===task end 2018-06-12 16:28:46.031 [taskExecutor-4] INFO service.task.testTask -taskExecutor-4===task run
经过日志咱们能够看到,再第100条线程也开始执行任务后,没有新的线程再被建立,而是等待有线程执行完后,再开始执行本次任务。线程
虽然上面的方式已经解决了咱们的问题,可是总以为不太好,有时候咱们须要异步执行任务,可是又不须要这么多的线程的时候,咱们可使用下面的配置来设置线程池的大小
配置文件:日志
<task:annotation-driven scheduler="testScheduler" /> <!-- 配置任务线程池和线程池大小 --> <task:scheduler id="testScheduler" pool-size="6" />
测试代码:code
@Scheduled(cron = "0/2 * * * * ?") @Async public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(6*1_000); logger.info(Thread.currentThread().getName()+"===task end"); }
结果日志:视频
2018-06-12 18:32:56.032 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task run 2018-06-12 18:32:58.007 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task run 2018-06-12 18:33:00.005 [taskExecutor-3] INFO service.task.testTask -taskExecutor-3===task run 2018-06-12 18:33:02.008 [taskExecutor-4] INFO service.task.testTask -taskExecutor-4===task run 2018-06-12 18:33:02.036 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task end 2018-06-12 18:33:04.327 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task end 2018-06-12 18:33:04.328 [taskExecutor-5] INFO service.task.testTask -taskExecutor-5===task run 2018-06-12 18:33:06.007 [taskExecutor-6] INFO service.task.testTask -taskExecutor-6===task run 2018-06-12 18:33:06.010 [taskExecutor-3] INFO service.task.testTask -taskExecutor-3===task end 2018-06-12 18:33:08.459 [taskExecutor-4] INFO service.task.testTask -taskExecutor-4===task end 2018-06-12 18:33:08.460 [taskExecutor-7] INFO service.task.testTask -taskExecutor-7===task run 2018-06-12 18:33:10.011 [taskExecutor-8] INFO service.task.testTask -taskExecutor-8===task run 2018-06-12 18:33:10.332 [taskExecutor-5] INFO service.task.testTask -taskExecutor-5===task end 2018-06-12 18:33:12.005 [taskExecutor-9] INFO service.task.testTask -taskExecutor-9===task run 2018-06-12 18:33:12.012 [taskExecutor-6] INFO service.task.testTask -taskExecutor-6===task end 2018-06-12 18:33:14.904 [taskExecutor-10] INFO service.task.testTask -taskExecutor-10===task run 2018-06-12 18:33:14.904 [taskExecutor-7] INFO service.task.testTask -taskExecutor-7===task end
结果和咱们预料的并不同啊,线程数超过了6,这是什么缘由呢?get
其实若是咱们在使用@Async时想使用配置好的线程池,须要为@Async注解添加value属性来制定所用的线程池。
修改后的代码
@Scheduled(cron = "0/2 * * * * ?") @Async("testScheduler") public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(30*1_000); logger.info(Thread.currentThread().getName()+"===task end"); }
结果日志:
2018-06-12 18:54:42.035 [testScheduler-3] INFO service.task.testTask -testScheduler-3===task run 2018-06-12 18:54:44.010 [testScheduler-2] INFO service.task.testTask -testScheduler-2===task run 2018-06-12 18:54:46.007 [testScheduler-1] INFO service.task.testTask -testScheduler-1===task run 2018-06-12 18:54:48.007 [testScheduler-5] INFO service.task.testTask -testScheduler-5===task run 2018-06-12 18:54:50.005 [testScheduler-4] INFO service.task.testTask -testScheduler-4===task run 2018-06-12 18:54:52.021 [testScheduler-6] INFO service.task.testTask -testScheduler-6===task run 2018-06-12 18:55:12.039 [testScheduler-3] INFO service.task.testTask -testScheduler-3===task end 2018-06-12 18:55:12.044 [testScheduler-3] INFO service.task.testTask -testScheduler-3===task run 2018-06-12 18:55:14.016 [testScheduler-2] INFO service.task.testTask -testScheduler-2===task end 2018-06-12 18:55:14.022 [testScheduler-2] INFO service.task.testTask -testScheduler-2===task run 2018-06-12 18:55:16.289 [testScheduler-1] INFO service.task.testTask -testScheduler-1===task end 2018-06-12 18:55:16.297 [testScheduler-1] INFO service.task.testTask -testScheduler-1===task run 2018-06-12 18:55:18.289 [testScheduler-5] INFO service.task.testTask -testScheduler-5===task end 2018-06-12 18:55:18.293 [testScheduler-5] INFO service.task.testTask -testScheduler-5===task run 2018-06-12 18:55:20.009 [testScheduler-4] INFO service.task.testTask -testScheduler-4===task end 2018-06-12 18:55:20.014 [testScheduler-4] INFO service.task.testTask -testScheduler-4===task run 2018-06-12 18:55:22.165 [testScheduler-6] INFO service.task.testTask -testScheduler-6===task end 2018-06-12 18:55:22.172 [testScheduler-6] INFO service.task.testTask -testScheduler-6===task run
此次结果和咱们的预计是同样的了,在初始的6条线程使用完毕之后就会等待以前的线程释放啦,同时也能够看到线程池名是咱们设置的线程池。
若有错误,欢迎留言指正,谢谢你们!
提供一些优秀的IT视频资料,可免费下载!如须要请查看https://www.592xuexi.com