定时任务的10种写法,长见识了
定时任务的10种写法,长见识了
前⾔
最近有⼏个读者私信给我,问我他们的业务场景,要⽤什么样的定时任务。确实,在不⽤的业务场景下要⽤不同的定时任务,其实我们的选择还是挺多的。我今天给⼤家总结10种⾮常实⽤的定时任务,总有⼀种是适合你的。
⼀. linux⾃带的定时任务
crontab
不知道你有没有遇到过这种场景:有时需要临时统计线上的数据,然后导出到excel表格中。这种需求有时较为复杂,光靠写sql语句是⽆法满⾜需求的,这就需要写java代码了。然后将该程序打成⼀个jar包,在线上环境执⾏,最后将⽣成的excel⽂件下载到本地。
为了减⼩对线上环境的影响,我们⼀般会选择在凌晨1-2点,趁⽤户量少的时候,执⾏统计程序。(其实凌晨4点左右,⽤户才是最少的)由于时间太晚了,我们完全没必要守在那⾥等执⾏结果,⼀个定时任务就能可以搞定。
那么,这种情况⽤哪种定时任务更合适呢?
答案是:linux系统的crontab。(不过也不排除有些项⽬没部署在linux系统中)
运⾏crontab -e,可以编辑定时器,然后加⼊如下命令:
0 2 * * * /usr/local/java/jdk1.8/bin/java -jar /data/app/tool.jar > /logs/tool.log &
就可以在每天凌晨2点,定时执⾏tool.jar程序,并且把⽇志输出到tool.log⽂件中。当然你也可以把后⾯的执⾏java程序的命令写成shell脚本,更⽅便维护。
使⽤这种定时任务⽀持⽅便修改定时规则,有界⾯可以统⼀管理配置的各种定时脚本。
crontab命令的基本格式如下:
crontab [参数] [⽂件名]
如果没有指定⽂件名,则接收键盘上输⼊的命令,并将它载⼊到crontab。
参数功能对照表如下:
参数功能-u指定⽤户-e编辑某个⽤户的crontab⽂件内容-l显⽰某个⽤户的crontab⽂件内容-r删除某⽤户的crontab⽂件-i删除某⽤户的crontab⽂件时需确认
以上参数,如果没有使⽤-u指定⽤户,则默认使⽤的当前⽤户。
通过crontab -e命令编辑⽂件内容,具体语法如下:
[分] [⼩时] [⽇期] [⽉] [星期] 具体任务
其中:
分,表⽰多少分钟,范围:0-59
⼩时,表⽰多少⼩时,范围:0-23
⽇期,表⽰具体在哪⼀天,范围:1-31
⽉,表⽰多少⽉,范围:1-12
星期,表⽰多少周,范围:0-7,0和7都代表星期⽇
还有⼀些特殊字符,⽐如:
*代表如何时间,⽐如:*1*** 表⽰每天凌晨1点执⾏。
/
代表每隔多久执⾏⼀次,⽐如:*/5 **** 表⽰每隔5分钟执⾏⼀次。
,代表⽀持多个,⽐如:10 7,9,12 *** 表⽰在每天的7、9、12点10分各执⾏⼀次。
-代表⽀持⼀个范围,⽐如:10 7-9 *** 表⽰在每天的7、8、9点10分各执⾏⼀次。
此外,顺便说⼀下crontab需要crond服务⽀持,crond是linux下⽤来周期地执⾏某种任务的⼀个守护进程,在安装linux操作系统后,默认会安装crond服务⼯具,且crond服务默认就是⾃启动的。crond进程每分钟会定期检查是否有要执⾏的任务,如果有,则会⾃动执⾏该任务。
可以通过以下命令操作相关服务:
service crond status // 查看运⾏状态
service crond start //启动服务
service crond stop //关闭服务
service crond restart //重启服务
service crond reload //重新载⼊配置
使⽤crontab的优缺点:
优点:⽅便修改定时规则,⽀持⼀些较复杂的定时规则,通过⽂件可以统⼀管理配好的各种定时脚本。
缺点:如果定时任务⾮常多,不太好,⽽且必须要求操作系统是linux,否则⽆法执⾏。
⼆. jdk⾃带的定时任务
1.Thread
各位亲爱的朋友,你没看错,Thread类真的能做定时任务。如果你看过⼀些定时任务框架的源码,你最后会发现,它们的底层也会使⽤Thread类。
实现这种定时任务的具体代码如下:
public static void init() {
new Thread(() -> {
while (true) {
try {
System.out.println("doSameThing");
Thread.sleep(1000 * 60 * 5);
} catch (Exception e) {
<(e);
}
阡陌交错}
}).start();
手机如何恢复删除的聊天记录}
使⽤Thread类可以做最简单的定时任务,在run⽅法中有个while的死循环(当然还有其他⽅式),执⾏我们⾃⼰的任务。有个需要特别注意的地⽅是,需要⽤atch捕获异常,否则如果出现异常,就直接退出循环,下次将⽆法继续执⾏了。
这种⽅式做的定时任务,只能周期性执⾏,不能⽀持定时在某个时间点执⾏。
此外,该线程可以定义成守护线程,在后台默默执⾏就好。
使⽤场景:⽐如项⽬中有时需要每隔10分钟去下载某个⽂件,或者每隔5分钟去读取模板⽂件⽣成静态html页⾯等等,⼀些简单的周期性任务场景。
使⽤Thread类的优缺点:
优点:这种定时任务⾮常简单,学习成本低,容易⼊⼿,对于那些简单的周期性任务,是个不错的选择。
缺点:不⽀持指定某个时间点执⾏任务,不⽀持延迟执⾏等操作,功能过于单⼀,⽆法应对⼀些较为复杂的场景。
2.Timer
Timer类是jdk专门提供的定时器⼯具,⽤来在后台线程计划执⾏指定任务,在java.util包下,要跟TimerTask⼀起配合使⽤。
Timer类其实是⼀个任务调度器,它⾥⾯包含了⼀个TimerThread线程,在这个线程中⽆限循环从TaskQueue中获取TimerTask(该类实现了Runnable接⼝),调⽤其run⽅法,就能异步执⾏定时任务。我们需要继承TimerTask类,实现它的run⽅法,在该⽅法中加上⾃⼰的业务逻辑。
实现这种定时任务的具体代码如下:
public class TimerTest {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("doSomething");
}
},2000,1000);
}
}
先实例化⼀个Timer类,然后调⽤它的schedule⽅法,在该⽅法中实例化TimerTask类,业务逻辑写在run⽅法中。schedule⽅法最后的两次参数分别表⽰:延迟时间 和间隔时间,单位是毫秒。上⾯例⼦中,设置的定时任务是每隔1秒执⾏⼀次,延迟2秒执⾏。
主要包含6个⽅法:
schedule(TimerTask task, Date time), 指定任务task在指定时间time执⾏
schedule(TimerTask task, long delay), 指定任务task在指定延迟delay后执⾏
schedule(TimerTask task, Date firstTime,long period),指定任务task在指定时间firstTime执⾏后,进⾏重复固定延迟频率peroid 的执⾏
schedule(TimerTask task, long delay, long period), 指定任务task 在指定延迟delay 后,进⾏重复固定
延迟频率peroid的执⾏scheduleAtFixedRate(TimerTask task,Date firstTime,long period), 指定任务task在指定时间firstTime执⾏后,进⾏重复固定延迟频率peroid的执⾏
scheduleAtFixedRate(TimerTask task, long delay, long period), 指定任务task 在指定延迟delay 后,进⾏重复固定延迟频率peroid的执⾏
不过使⽤Timer实现定时任务有以下问题:
1. 由于Timer是单线程执⾏任务,如果其中⼀个任务耗时⾮常长,会影响其他任务的执⾏。
2. 如果TimerTask抛出RuntimeException,Timer会停⽌所有任务的运⾏。
使⽤Timer类的优缺点:
优点:⾮常⽅便实现多个周期性的定时任务,并且⽀持延迟执⾏,还⽀持在指定时间之后⽀持,功能还算强⼤。
缺点:如果其中⼀个任务耗时⾮常长,会影响其他任务的执⾏。并且如果TimerTask抛出RuntimeException,Timer会停⽌所有任务的运⾏,所以阿⾥巴巴开发者规范中不建议使⽤它。
3.ScheduledExecutorService
ScheduledExecutorService是JDK1.5+版本引进的定时任务,该类位于urrent并发包下。
ScheduledExecutorService是基于多线程的,设计的初衷是为了解决Timer单线程执⾏,多个任务之间会互相影响的问题。
它主要包含4个⽅法:
schedule(Runnable command,long delay,TimeUnit unit),带延迟时间的调度,只执⾏⼀次,调度之后可通过()阻塞直⾄任务执⾏完毕。
schedule(Callable<V> callable,long delay,TimeUnit unit),带延迟时间的调度,只执⾏⼀次,调度之后可通过()阻塞直⾄任务执⾏完毕,并且可以获取执⾏结果。
scheduleAtFixedRate,表⽰以固定频率执⾏的任务,如果当前任务耗时较多,超过定时周期period,则当前任务结束后会⽴即执⾏。
scheduleWithFixedDelay,表⽰以固定延时执⾏任务,延时是相对当前任务结束为起点计算开始时间。
实现这种定时任务的具体代码如下:
public class ScheduleExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = wScheduledThreadPool(5);
scheduledExecutorService.scheduleAtFixedRate(() -> {
System.out.println("doSomething");
},1000,1000, TimeUnit.MILLISECONDS);
咖啡猫语录}
}
调⽤ScheduledExecutorService类的scheduleAtFixedRate⽅法实现周期性任务,每隔1秒钟执⾏⼀次,每次延迟1秒再执⾏。
这种定时任务是阿⾥巴巴开发者规范中⽤来替代Timer类的⽅案,对于多线程执⾏周期性任务,是个不错的选择。ScheduledExecutorService的优缺点:
优点:基于多线程的定时任务,多个任务之间不会相关影响,⽀持周期性的执⾏任务,并且带延迟功能。
缺点:不⽀持⼀些较复杂的定时规则。
三. spring⽀持的定时任务
胡彦斌的微博1.spring task
spring task是spring3以上版本⾃带的定时任务,实现定时任务的功能时,需要引⼊spring-context包,⽬前它⽀持:xml 和 注解 两种⽅式。
送男朋友什么花最好
1. 项⽬实战
由于xml⽅式太古⽼了,我们以springboot项⽬中注解⽅式为例。
第⼀步,在l⽂件中引⼊spring-context相关依赖。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
第⼆步,在springboot启动类上加上@EnableScheduling注解。
@EnableScheduling
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
第三步,使⽤@Scheduled注解定义定时规则。
@Service
public class SpringTaskTest {
@Scheduled(cron = "${sue.}")
public void fun() {
System.out.println("doSomething");
}
}
第四步,在applicationContext.properties⽂件中配置参数:
sue.=*/10 * * * * ?
这样就能每隔10秒执⾏⼀次fun⽅法了。
2. cron规则
spring4以上的版本中,cron表达式包含6个参数:
>明星大侦探恐怖童谣

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。