java如何定时执行一个任务,java定时任务怎么触发
00-1010 1使用java.util.Timer2使用ScheduledExecutorService3使用Spring任务摘要
00-1010这种方式的计时任务主要使用两个类,Timer和TimerTask,使用起来比较简单。Timer负责设置TimerTask的开始和间隔执行时间。TimerTask是一个抽象类。新的时候可以实现自己的run方法,然后扔给Timer执行。
代码示例:
导入Java . time . local datetime;导入Java . util . timer;导入Java . util . timertask;public class Schedule { public static void main(String[]args){ TimerTask TimerTask=new TimerTask(){ @ Override public void run(){ system . out . println( current thread: thread . current thread()。getName()当前时间 local datetime . now());} };//在指定的0毫秒延迟后启动,然后执行Timertask Newtimer()。以2000毫秒的间隔调度(Timertask,0L,2000 l);System.out.println(当前线程: Thread.currentThread()。getName()当前时间 local datetime . now());}}
缺点:
定时器后面只有一个线程,无论有多少任务,都只有一个工作线程串行执行,所以效率低下是被单线程限制的。如果第一个任务逻辑上是无止境的,那么后续的任务都不会因为单线程而执行。任何一个任务抛出异常后,整个定时器都会结束,后续的所有任务都无法执行。
00-1010 scheduledexecutorservice是Timer的替代,JDK 1.5是通过收缩引入的,是基于线程池设计的定时任务类。每个调度任务都会分配到线程池中的某一个线程去执行,任务就是并发调度执行的,任务之间互不影响.
Java 5.0引入了java.util.concurrent包,其中一个并发实用程序是ScheduledThreadPoolExecutor,这是一个线程池,用于以给定的速率或延迟重复任务。它实际上是Timer/TimerTask组合的更通用的替代方案,因为它允许多个服务线程,接受各种时间单位,并且不需要TimerTask子类(只需实现Runnable)。使用线程将ScheduledThreadPoolExecutor配置为等同于Timer。
代码示例:
导入Java . time . local datetime;导入Java . util . concurrent . *;class schedule { public static void main(string[]args){//创建一个包含5个核心线程的ScheduledThreadPoolExecutor线程池scheduledexecutorservice scheduledexecutorservice=new ScheduledThreadPoolExecutor(5);//创建一个可运行的打印当前线程和当前时间Runnable r=()-system . out . println( current thread: thread . current thread()。getName()当前时间 local datetime . now());/** * schedule:只调度一次* scheduleAtFixedRate:开始时计算间隔时间,如果任务超过间隔时间,则直接开始下一个任务* scheduleWithFixedDelay:不管一个任务执行多久,都要等上一轮任务完成后再开始下一个任务*/
// 在指定1秒延迟后执行r,之后每两秒执行一次 scheduledExecutorService.scheduleAtFixedRate(r, 1, 2, TimeUnit.SECONDS); }}
3 使用Spring Task
Spring Task 底层是基于 JDK 的 ScheduledThreadPoolExecutor 线程池来实现的。直接通过Spring 提供的 @Scheduled 注解即可定义定时任务,非常方便。
以Spring Boot来作为示例,步骤为
在启动类所在包下创建Schedule 类(在没有配置@ComponentScan的情况下,Spring Boot只会默认扫描启动类所在包的spring组件)在该类上添加@Component和@EnableScheduling注解在方法上添加@Scheduled注解,该注解主要参数如下
String cron() default ""; // 支持cron表达式long fixedDelay() default -1; // 在最后一次调用结束和下一次调用开始之间的时间间隔,以毫秒为单位String fixedDelayString() default ""; // 同上,类似ScheduledExecutorService的scheduleWithFixedDelaylong fixedRate() default -1; // 在调用之前的时间间隔,以毫秒为单位String fixedRateString() default ""; // 同上,类似ScheduledExecutorService的scheduleAtFixedRatelong initialDelay() default -1; // 在第一次执行fixedRate()或fixedDelay()任务之前要延迟的毫秒数String initialDelayString() default ""; // 同上
代码示例:
import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.time.LocalDateTime;@Component@EnableSchedulingpublic class Schedule { @Scheduled(fixedRate = 2000L) public void task() { System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前时间" + LocalDateTime.now()); }}
优点: 简单,轻量,支持 Cron 表达式缺点 :默认只支持单机,是单线程的,并且提供的功能比较单一
可以通过@EnableAsync和 @Async开启多线程
import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.time.LocalDateTime;@Component@EnableAsync // 开启异步多线程@EnableSchedulingpublic class Schedule { @Async @Scheduled(fixedRate = 2000L) public void task() { System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前时间" + LocalDateTime.now()); }}
使用@EnableAsync注解后,默认情况下,Spring将搜索关联的线程池定义:上下文中的唯一org.springframework.core.task.TaskExecutor的bean,或者名为taskExecutor的java.util.concurrent.Executor的bean。如果两者都无法解析,则将使用org.springframework.core.task.SimpleAsyncTaskExecutor来处理异步方法调用。
TaskExecutor实现为每个任务启动一个新线程,异步执行它。 支持通过concurrencyLimitbean 属性限制并发线程。默认情况下,并发线程数是无限的,所以使用默认的线程池有导致内存溢出的风险。
注意:刚才的运行结果看起来是线程复用的,而实际上此实现不重用线程!应尽量实现一个线程池TaskExecutor ,特别是用于执行大量短期任务。不要使用默认的SimpleAsyncTaskExecutor。
import org.springframework.context.annotation.Bean;import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.util.concurrent.Executor;@Component@EnableAsync@EnableSchedulingpublic class Schedule { @Async @Scheduled(fixedRate = 2000L) public void task() { System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前时间" + LocalDateTime.now()); } @Bean("taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(10); taskExecutor.setMaxPoolSize(50); taskExecutor.setQueueCapacity(200); taskExecutor.setKeepAliveSeconds(60); taskExecutor.setThreadNamePrefix("自定义-"); taskExecutor.setAwaitTerminationSeconds(60); return taskExecutor; }}
上面提到的一些定时任务的解决方案都是在单机下执行的,适用于比较简单的定时任务场景比如每天凌晨备份一次数据。如果我们需要一些高级特性比如支持任务在分布式场景下的分片和高可用的话,我们就需要用到分布式任务调度框架了,比如Quartz、Elastic-Job、XXL-JOB、PowerJob,本文就不再详细进行介绍了,感兴趣的可以自行查阅相关资料。
总结
到此这篇关于Java项目实现定时任务的三种方法的文章就介绍到这了,更多相关Java定时任务实现内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。