关于定时器的总结

来源:互联网 发布:照片移花接木软件下载 编辑:程序博客网 时间:2024/06/06 04:39

        项目中用到过定时器的知识点,发现其实并不简单,在此总结下。关于定时目前2种技术能解决,一种是轻量级的Java Timer,另一种是重量级的Quartz。


关于Java Timer

          Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务。


关于Timer一个简单的例子:

        Timer timer = new Timer();        timer.schedule(new TimerTask() {            public void run() {                System.out.println("11232");            }        }, 200000 , 1000);

       schedule是一个定时调度的方法,里面有多个方法,每个方法代表的意义不同,例如当前的Demo表示的是200秒后开始执行,每一秒执行一次。Timer提供的定时调度的方法很多,能满足多种场景:


1、这个方法是调度一个task,经过delay(ms)后开始进行调度,仅仅调度一次。

 public void schedule(TimerTask task, long delay)

2、在指定的时间点time上调度一次。

public void schedule(TimerTask task, Date time)

3、这个方法是调度一个task,在delay(ms)后开始调度,每次调度完后,最少等待period(ms)后才开始调度。

public void schedule(TimerTask task, long delay, long period)

4、和上一个方法类似,唯一的区别就是传入的第二个参数为第一次调度的时间。

public void schedule(TimerTask task, Date firstTime, long period)


5、调度一个task,在delay(ms)后开始调度,然后每经过period(ms)再次调度,貌似和方法:schedule是一样的,其实不然,后面你会根据源码看到,schedule在计算下一次执行的时间的时候,是通过当前时间(在任务执行前得到) + 时间片,而scheduleAtFixedRate方法是通过当前需要执行的时间(也就是计算出现在应该执行的时间)+ 时间片,前者是运行的实际时间,而后者是理论时间点,例如:schedule时间片是5s,那么理论上会在5、10、15、20这些时间片被调度,但是如果由于某些CPU征用导致未被调度,假如等到第8s才被第一次调度,那么schedule方法计算出来的下一次时间应该是第13s而不是第10s,这样有可能下次就越到20s后而被少调度一次或多次,而scheduleAtFixedRate方法就是每次理论计算出下一次需要调度的时间用以排序,若第8s被调度,那么计算出应该是第10s,所以它距离当前时间是2s,那么再调度队列排序中,会被优先调度,那么就尽量减少漏掉调度的情况。

public void scheduleAtFixedRate(TimerTask task, long delay, long period)

6、方法同上,唯一的区别就是第一次调度时间设置为一个Date时间,而不是当前时间的一个时间片,我们在源码中会详细说明这些内容。

public void scheduleAtFixedRate(TimerTask task, Date firstTime,long period)


关于Timer在实际使用方面,和java多线程一样有两种方式:

一种是通过多线程的方式运行:


package cn.xdf.dtmanager.quartz;import java.text.SimpleDateFormat;import java.util.Date;import java.util.TimerTask;/** * Created by fengch on 2017/9/21. */public class MyTask extends TimerTask {    private String name;    private int age;    public MyTask(String name, int age) {        this.name = name;        this.age = age;    }    @Override    public void run() {        SimpleDateFormat sdf = null;        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");        System.out.println("当前时间:" + sdf.format(new Date()) + "---------------------" + this.name + ":::" + this.age);    }}

Timer t = new Timer(); // 建立Timer对象t.schedule( new MyTask("多吃点", 1), DateUtil.StringToDate(time1,DateUtil.DATATIME_FORMMATER));



另一种是通过匿名类不类的方式(java8可以通过lambda方式):

       就是如上所写的一个demo!

关于Quartz

       quartz是一个很好的定时job框架,在时间节点配置方面特别的好。所以关于Quartz方面的内容也是特别的多,笔者在这里也是班门弄斧。在多机器部署的时候,可想而知要是一个多个定时都被执行一次,会产生很多错误的可能。所以本篇只介绍使用Quartz这是为leader模式!



多台服务器部署时候,只有其中一台服务器是leader,只有当leader主机挂了的时候,另外一台following并自动成为主机。quartz分三个线程进行完成leader模式的设计:

一、集群任务调度线程

此任务调度的作用是:修改当前服务器的时间为系统的当前时间,将过期的服务状态变更为停止:

package com.lgy.core.task;import com.lgy.comm.Constant;import com.lgy.core.base.AbstractTask;import com.lgy.service.ServInfoService;import org.apache.log4j.Logger;import org.quartz.JobExecutionContext;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;/** * 集群任务调度线程的定时任务类 * @author yuejing * @date 2015年3月29日 下午10:05:34 * @version V1.0.0 */@Componentpublic class MainTask extends AbstractTask {private static final Logger LOGGER = Logger.getLogger(MainTask.class);@Autowiredprivate ServInfoService servInfoService;@Overridepublic void execute(JobExecutionContext context) {System.out.println("=========================== 执行了MainTask ====================");//=========================== 发送任务心跳(间隔10s) begin ====================//修改当前服务的updatetime为当前时间servInfoService.updateUpdatetimeByServid(Constant.serviceCode());//将过期的服务状态变更为停止servInfoService.updateDestroy();//=========================== 发送任务心跳(间隔10s) end ====================}}



二、leader选举调度线程


流程图如下:




三、清除过期调度线程

此任务调度的作用是:删除过期已经销毁的服务,将已经销毁的服务设置为非leader:

package com.lgy.core.task;import com.lgy.core.base.AbstractTask;import com.lgy.service.ServInfoService;import com.lgy.utils.FrameTimeUtil;import org.apache.log4j.Logger;import org.quartz.JobExecutionContext;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.util.Date;/** * 清空任务日志的定时任务类 * @author yuejing * @date 2015年3月29日 下午10:05:34 * @version V1.0.0 */@Componentpublic class CleanTask extends AbstractTask {private static final Logger LOGGER = Logger.getLogger(CleanTask.class);@Autowiredprivate ServInfoService servInfoService;@Overridepublic void execute(JobExecutionContext context) {System.out.println("=========================== CleanTask ====================");String siValue = "7";Date siDate = FrameTimeUtil.addDays(FrameTimeUtil.getTime(), - Integer.valueOf(siValue));//清空小于指定日期的已停止的服务servInfoService.deleteDestroyLtDate(siDate);//修改已销毁的服务为非LeaderservInfoService.destroyLeader();}}


有兴趣参考:

https://gitee.com/yuejing/task 

原创粉丝点击