在实际开发中经常用到定时任务,如定时清理数据,备份数据,报表统计等。java中怎么实现定时任务呢?
1、通过线程,定时睡眠方法执行定时任务
创建一个thread,在它在run方法里面写个while循环一直运行着,在循环体内部写个thread.sleep睡眠一段时间来达到定时任务的效果。这样使用起来很方便但是缺点很多。比如:不方便设计到具体时间点运行。
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
System.out.println("show time="+System.currentTimeMillis());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
2、通过Java.util中的timer 和timerTask实现定时任务。
相比与使用线程定时睡眠,好处是可以控制启动任务和取消任务,可以设置执行延时,可以设计到具体时间点启动,可以设置运行频率。
long delay=1000;
long period=1000;
Timer tr=new Timer();
tr.schedule(new TimerTask() {
int i=0;
@Override
public void run() {
if(i++==5){tr.cancel();}
System.out.println(System.currentTimeMillis());
}
}, delay,period);
还可以作为守护线程运行: 实现方式 new Timer(true) true 说明这个timer以daemon方式运行
什么是守护线程呢?
用个比较通俗的说法,任何一个守护线程都是整个JVM中所有非守护线程的保姆:
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。
3、通过线程池的ScheduledExecutorService执行定时任务
他是Executors的静态方法,Executors常用的有四个生成线程池的静态方法,其他三个分别是:newSingleThreadpool():单线程池,同时只有一个线程在跑。
newCachedThreadPool() :回收型线程池,可以重复利用之前创建过的线程,运行线程最大数是Integer.MAX_VALUE。
newFixedThreadPool() :固定大小的线程池,跟回收型线程池类似,只是可以限制同时运行的线程数量
我们重点说下scheduledExecutorService,他和timer的区别是:
Timer的内部只有一个线程,如果有多个任务的话就会顺序执行,这样我们的延迟时间和循环时间就会出现问题。
ScheduledExecutorService是线程池,所以就不会出现这个情况,在对延迟任务和循环任务要求严格的时候,就需要考虑使用ScheduledExecutorService了。
4、除此之外还有一些常用的框架可以使用long initialDelay=1000; long period=2000; ScheduledExecutorService st=Executors.newSingleThreadScheduledExecutor(); st.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(System.currentTimeMillis()); } }, initialDelay, period, TimeUnit.MILLISECONDS);
Spring 定时任务 springTaskTimer
Quartz 是一个使用频率非常高的框架,他的优点也很突出:
Quartz支持Cron表达式定义时间点也支持SimpleTrigger对应时间点,可以很精确的定义时间点。
Quartz支持集群,可以在多个服务器(连同一个数据库)自动分配到不同的服务器上执行。
Quartz支持多种错误处理形式(如错误后下次不执行、马上重新执行、下次继续执行等)
Quartz支持多种漏触发处理(如关机漏触发情况)
******如果需要可以打开蜻蜓FM搜索”java面试题“收听音频面视题****