Java——定时任务调度工具


一、什么是定时任务调度?

基于给定的时间点、给定的时间间隔或者给定的执行次数自动执行的任务。

1、常用的定时调度工具:Timer和Quartz

对时间的控制上,能实现简单的定时任务。

若特定时间的定时任务,需要用Quartz,它的定时机制更加庞大。

Quartz可以使用多个执行线程来实现。

二、Timer简介

1、Timer的定义以及架构

Timer定义:java.lang.object,是java.util.Timer包下。

一个后台的线程,后台线程支持多个目录定时执行。

有且仅有一个后台线程多个业务线程进行定时定频率的调度。

主要构件:

Timer——>定时调用——>TimerTask(业务线程)。

Timer

TimerThread后台执行的线程。

TimerTask对应的业务线程, TimerThread通过定期的调用TimerTask的run方法来实现定时调度。

2、Timer示例

import java.util.TimerTask;

public class MytimerTask extends TimerTask{
    private String name;
    //添加name的set和get方法
    public MyTimerTask(String inputname){
        name=inputname;
    }

    @Override
    public void run(){
        //打印输出内容:
        out.print("test"+name);
    }
}
public class Mytimer{

    public static void main(String[] args){
        //1:创建一个timer实例
        Timer timer = new Timer();
        //2:创建一个MyTimerTask实例
        MyTimeTask myTimerTask = new MyTimerTask("No.1");
        //3:通过timer定时定频率调用MyTimerTask的业务逻辑
        //即第一次执行是在当前时间的两秒之后,之后每隔一秒钟执行一次
        timer.schedule(myTimerTask,2000L,1000L);
    }
}

三、Timer的定时调度函数

1、schedule的四种用法

①、chedule(task,time):参数:

  • task - 所要安排的任务
  • time - 执行任务的时间

作用:在时间等于或超过time的时候执行切仅执行一次task;

②、schedule(task,time,period):参数

  • task - 所要安排的任务
  • time - 执行任务的时间
  • period - 执行一次task的时间间隔,单位是毫秒

作用:时间等于或超过time时首次执行task,之后每隔period毫秒重复执行一次task。

③、schedule(task,delay):参数

  • task - 所要安排的任务
  • delay - 执行任务前的延迟时间,单位是毫秒

作用:等待delay毫秒后执行且仅执行一次task。

④、 schedule(task,delay,period):参数

  • task - 所要安排的任务
  • delay - 执行任务前的延迟时间,单位是毫秒
  • period - 执行一次task的时间间隔,单位是毫秒

作用:等待delay毫秒后首次执行task,之后每隔period毫秒重复执行一次task。

import java.util.TimerTask;

public class MytimerTask extends TimerTask{
    private String name;
    //添加name的set和get方法
    public MyTimerTask(String inputname){
        name=inputname;
    }

    @Override
    public void run(){
        //以yyyy-MM-dd HH:mm:ss的格式打印当前执行时间
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //打印当前执行时间
        out.print("当前时间:"+sf.format(calendar.getTime()));


        //打印name:
        out.print("test"+name);
    }
}
public class Mytimer{

    public static void main(String[] args){
        //1:创建一个timer实例
        Timer timer = new Timer();
        //2:创建一个MyTimerTask实例
        MyTimeTask myTimerTask = new MyTimerTask("No.1");
        //3:通过timer定时定频率调用MyTimerTask的业务逻辑
        //即第一次执行是在当前时间的两秒之后,之后每隔一秒钟执行一次
        //timer.schedule(myTimerTask,2000L,1000L);


        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //打印当前执行时间
        out.print("当前时间:"+sf.format(calendar.getTime()));
        //设置3秒之后的时间
        calendar.add(Calendar.SECOND,3);

        //schedule的用法
        /**
        * 1、在时间等于或超过time的时候执行且仅执行一次task
        /

        myTimerTask.setName("schedule1");
        timer.schedule(myTimerTask,calendar.getTime());

        /**
        *2、时间等于或超过time时首次执行task
        *之后每隔period毫秒重复执行一次task
        /
        myTimerTask.setName("schedule2");
        //每隔2秒钟,重复执行myTimerTask方法中的run方法
        timer.schedule(myTimerTask,calendar.getTime(),2000);
    }

        /**
        *3、等待delay毫秒后执行且仅执行一次task
        *如现在是00:00:00
        *则在00:00:01执行一次task,打印任务的名字
        /
        myTimerTask.setName("schedule3");
        timer.schedule(myTimerTask,1000);

        /**
        *4、等待delay毫秒后首次执行task,之后每隔period毫秒重复执行一次task
        /
        myTimerTask.setName("schedule4");
        timer.schedule(myTimerTask,3000,2000);

}

2、scheduleAtFixedRate的两种用法

scheduleAtFixedRate(task,time,period) :参数
- task - 所要安排的任务
- time- 首次执行任务的时间
- period - 执行一次task的时间间隔,单位是毫秒

作用:时间等于或超过time时首次执行task,之后每隔period毫秒重复执行一次task。

scheduleAtFixedRate(task,delay,period) :参数
- task - 所要安排的任务
- delay- 执行任务前的延迟时间,单位是毫秒
- period - 执行一次task的时间间隔,单位是毫秒

作用:时间等于或超过time时首次执行task,之后每隔period毫秒重复执行一次task。

    /**
    *1、时间等于或超过timer时首次执行task,之后每隔period毫秒重复执行一次task
    /
    myTimerTask.setName("scheduleAtFixedRate1");
    timer.scheduleAtFixedRate(myTimerTask,calendar.getTime(),2000);

    /**
    *2、等待delay毫秒后首次执行task,之后每隔period毫秒重复执行一次task  
    /
    myTimerTask.setName("scheduleAtFixedRate2");
    timer.scheduleAtFixedRate(myTimerTask,3000,2000);

四、其他重要函数

1、TimerTask的cancel(),scheduleExecutionTime()

cancel():

作用:取消当前TimerTask里的任务

//计时器
private Integer count=0;

void run(){
    if(count < 3){
        //业务

        count++;
    }else{
        //任务取消
        cancel();
    }
}

scheduleExecutionTime():

作用:返回此任务最近实际执行的已安排执行的时间
返回值:最近发生此任务执行安排的时间,为long型。

    myTimerTask.setName("schedule");
    timer.scheduleAtFixedRate(myTimerTask,3000);
    out.print("test":sf.format(myTimerTask.scheduleExecutionTime()));

2、Timer的cancel(),purge()

cancel()
作用:终止此计时器,丢弃所有当前已安排的任务。

    //休眠5秒
    Thread.sleep(5000);
    //取消当前所有任务
    timer.calcel();

purge():
作用:从此计时器的任务队列中移除所有已取消的任务。
返回值:从队列中移除的任务数。

    timer.schedule(task2,1000,2000);
    timer.purge();

    Thread.sleep(2000);
    Date cancelTimer = new Date();
    task2.cancel();

五、schedule与schduleAtFixedRate的区别

1、区别:首次计划执行的时间早于当前的时间

schdule:
“fixed-delay”:如果第一次执行时间被delay了,随后的执行时间按照上一次实际执行完成的时间点进行计算。

void main(String[] args){
    //规定时间格式
    final SimpleDateFormat sf = new SimpleDateFormat(yy:MM:dd mm:HH:ss)
    //获取当前时间
    Calendar calendar = Caledndar.getInstance();
    out.print("sf.format(calendar.getTime()));
    //设置成6秒前的时间,若当前时间为 00:00:06,
    //那么设置之后时间变成00:00:00
    calendar.add(Calendar.SECOND,-6);
    Timer timer = new Timer();
    //第一次执行时间为6秒前,之后每隔2秒钟执行一次
    timer.schedule(new TimerTask(){
        public void run(){
            //打印当前的计划执行时间
            out.print("test:"+sf.format(scheduleExecutionTimer()));
        }
    },calendar.getTimer(),2000);
}

schduleAtFixedRate方法:
“fixed-rate”:如果第一次执行时间被delay了,随后的执行时间按照上一次开始的时间点进行计算,并且为了赶上进度会多次执行任务,因此TimerTask中的执行体需要考虑同步

    timer.schduleAtFixedRate(new TimerTask(){
        public void run(){
            //打印当前的计划执行时间
            out.print("test:"+sf.format(scheduleExecutionTimer()));
        }
    },calendar.getTimer(),2000);

2、区别:任务执行所需时间超过任务的执行周期间隔

schdule方法:
下一次执行时间相对于上一次实际执行完成的时间点,因此执行时间会不断延后

void main(String[] args){
    //规定时间格式
    final SimpleDateFormat sf = new SimpleDateFormat(yy:MM:dd mm:HH:ss)
    //获取当前时间
    Calendar calendar = Caledndar.getInstance();
    out.print("sf.format(calendar.getTime()));
    Timer timer = new Timer();
    //第一次执行时间为6秒前,之后每隔2秒钟执行一次
    timer.schedule(new TimerTask(){
        public void run(){
            try{
                Thread.sleep(3000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            //打印当前的计划执行时间
            out.print("test:"+sf.format(scheduleExecutionTimer()));
        }
    },calendar.getTimer(),2000);
}

schduleAtFixedRate方法:
下一次执行时间相对于上一次开始的时间点,因此执行时间一般不会延后,因此存在并发性

timer.schduleAtFixedRate(new TimerTask(){
        public void run(){
            try{
                Thread.sleep(3000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            //打印当前的计划执行时间
            out.print("test:"+sf.format(scheduleExecutionTimer()));
        }
    },calendar.getTimer(),2000);

六、Timer的缺陷

1、管理并发任务的缺陷

Timer有且仅有一个后台的线程,并不支持任务与任务之间的并发;如果存在多个任务,且任务时间过长,会导致执行效果与预期不符;

第二个任务会在第一个任务执行完成后在执行自己的任务;

2、当任务抛出异常时的缺陷

如果 TimerTask抛出RuntimeException,Timer会停止所有任务的运行;

    throw new RuntiomeException();  

第一个任务如果抛出异常,则第二个任务就不会再继续执行了,直接从第一个任务开始终止执行;

3、Timer的使用禁区:

对时效性要求较高的多任务并发作业:

对复杂任务的调度;

猜你喜欢

转载自blog.csdn.net/An1090239782/article/details/80914955