Java实现定时任务
本文实例为大家分享了Java实现定时任务的具体代码,供大家参考,具体内容如下
1 使用java.util.Timer
这种方式的定时任务主要用到两个类,Timer 和 TimerTask,使用起来比较简单。其中 Timer 负责设定 TimerTask 的起始与间隔执行时间。 TimerTask是一个抽象类,new的时候实现自己的 run 方法,然后将其丢给 Timer 去执行即可。
代码示例:
缺点:
- Timer 的背后只有一个线程,不管有多少个任务,都只有一个工作线程串行执行,效率低下
- 受限于单线程,如果第一个任务逻辑上死循环了,后续的任务一个都得不到执行
- 依然是由于单线程,任一任务抛出异常后,整个 Timer 就会结束,后续任务全部都无法执行
2 使用ScheduledExecutorService
ScheduledExecutorService 即是 Timer 的替代者,JDK 1.5 并发包引入,是基于线程池设计的定时任务类。每个调度任务都会分配到线程池中的某一个线程去执行,任务就是并发调度执行的,任务之间互不影响。
Java 5.0引入了java.util.concurrent包,其中的并发实用程序之一是ScheduledThreadPoolExecutor ,它是一个线程池,用于以给定的速率或延迟重复执行任务。它实际上是Timer/TimerTask组合的更通用替代品,因为它允许多个服务线程,接受各种时间单位,并且不需要子类TimerTask (只需实现Runnable)。使用一个线程配置ScheduledThreadPoolExecutor使其等效于Timer 。
代码示例:
3 使用Spring Task
Spring Task 底层是基于 JDK 的 ScheduledThreadPoolExecutor 线程池来实现的。直接通过Spring 提供的 @Scheduled 注解即可定义定时任务,非常方便。
以Spring Boot来作为示例,步骤为
1.在启动类所在包下创建Schedule 类(在没有配置@ComponentScan的情况下,Spring Boot只会默认扫描启动类所在包的spring组件)
2.在该类上添加@Component和@EnableScheduling注解
3.在方法上添加@Scheduled注解,该注解主要参数如下
代码示例:
- 优点: 简单,轻量,支持 Cron 表达式
- 缺点 :默认只支持单机,是单线程的,并且提供的功能比较单一
可以通过@EnableAsync和 @Async开启多线程
使用@EnableAsync注解后,默认情况下,Spring将搜索关联的线程池定义:上下文中的唯一org.springframework.core.task.TaskExecutor
的bean,或者名为“taskExecutor”的java.util.concurrent.Executor
的bean。如果两者都无法解析,则将使用org.springframework.core.task.SimpleAsyncTaskExecutor来处理异步方法调用。
TaskExecutor实现为每个任务启动一个新线程,异步执行它。 支持通过“concurrencyLimit”bean 属性限制并发线程。默认情况下,并发线程数是无限的,所以使用默认的线程池有导致内存溢出的风险。
注意:刚才的运行结果看起来是线程复用的,而实际上此实现不重用线程!应尽量实现一个线程池TaskExecutor ,特别是用于执行大量短期任务。不要使用默认的SimpleAsyncTaskExecutor。
上面提到的一些定时任务的解决方案都是在单机下执行的,适用于比较简单的定时任务场景比如每天凌晨备份一次数据。如果我们需要一些高级特性比如支持任务在分布式场景下的分片和高可用的话,我们就需要用到分布式任务调度框架了,比如Quartz、Elastic-Job、XXL-JOB、PowerJob,本文就不再详细进行介绍了,感兴趣的可以自行查阅相关资料。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程学习网。