定时任务

简介:

日常生活中有多定时任务的应用场景,比如闹钟每天指定时间叫你起床,比如监控系统,隔断时间采集数据,对异常报警。

TimerTask和Timer:

TimerTask表示的时一个定时任务类,它是一个抽象类,实现了runnable接口,具体的定时任务类需要继承该类,实现run方法。

Timer:具体执行类,负责定时任务的调度和执行。Timer内部是有一任务队列和Timer线程组成。任务队列是一个基于堆实现的优先级队列,按照下次执行时间排优先级。因为只有一个线程,所有有时候任务会被延迟处理,且Timer线程主体是一个循环,循环处理任务队列中的任务。

Timer常用的方法:

方法名返回值说明
schedule(TimerTask task,Date time)void在绝对时间点执行任务
schedule(TimerTask task,long delay)void在当前时间延时delay毫秒后运行
schedule(TimerTask task,Date firstTime,long period)void固定延时重复执行,第一次执行时间时firstTime, 后面执行时间是上一次实际执行时间+period
schedule(TimerTask task,long delay,long period)固定延时重复执行, 当前时间+delay为第一次执行之间,后面的都是实际执行时间加period
scheduleAtFixedRate(TimerTask,Date firstTime,long period)void固定频率执行,第一次执行时间是firstTime,后面执行时间都是前一次实际执行时间+period
scheduleAtFixedRate(TimerTask,long delay,long period)void固定频率执行,第一次执行时间是当前时间+delay,后面每一次执行都是前一次实际执行时间+period
public class TimedTask {
    static class MyTimerTask extends TimerTask {

        @Override
        public void run() {
            System.out.println("定时任务1");
            try {
                Thread.sleep(2000);
            }catch (InterruptedException i){
                i.printStackTrace();
            }
            System.out.println("执行完毕");
        }
    }

    static class MineTimerTask extends TimerTask {

        @Override
        public void run() {
            System.out.println("定时任务2");
        }
    }
    static class LockTimerTask extends  TimerTask {

        @Override
        public void run() {
            while(true){
                System.out.println("定时任务会有死循环");
            }
        }
    }

    static class ExceptionTimerTask extends TimerTask {

        @Override
        public void run() {
            System.out.println("发生异常后所有定时任务都会被取消");
            throw new RuntimeException();
        }
    }
    public static void main(String[] args) throws Exception {
        Timer timer = new Timer();
        MyTimerTask myTimerTask = new MyTimerTask();
        MineTimerTask mineTimerTask = new MineTimerTask();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //指定绝对时间执行任务
        timer.schedule(myTimerTask,simpleDateFormat.parse("2021-3-17 10:33:00"));
        //当前时间加指定延时毫秒时间执行任务
        timer.schedule(myTimerTask,1000);
        //指定第一次执行时间按固定的延时时间重复执行
        timer.schedule(myTimerTask,simpleDateFormat.parse("2021-3-17 10:40:00"),1000);
        //当前时间+延时毫秒时间按固定延时时间重复执行
        timer.schedule(myTimerTask,1000,1000);
        //指定第一次执行时间,按固定频率指定的延时时间执行任务
        timer.schedule(myTimerTask,simpleDateFormat.parse("2021-3-17 10:42:00"),1000);
        //当前时间+延时时间按固定频率重复执行
        timer.schedule(myTimerTask,1000,1000);
        //timer内部主要是由任务队列和Timer线程两部分组成。任务队列是一个基于堆实现的优先级队列
        //按照下次执行的时间排优先级。Timer线程负责执行所有的定时任务,需要强调的是,一个Timer
        //对象只有一个Timer线程,所以下面的例子,任务二会延时处理。Timer线程主体是个循环,
        timer.schedule(myTimerTask,1000);
        timer.schedule(mineTimerTask,1000);
        //下面任务2会一下子处理多次任务,因为延时相对的是任务执行前的当前时间,所以固定频率会补足之前等待的时间的频率次数
        timer.schedule(myTimerTask,10);
        timer.scheduleAtFixedRate(mineTimerTask,100,1000);
        //因为Timer只有一个线程,所以当有一个人发生死循环时,后面的任务就永远无法执行了
        timer.schedule(myTimerTask,100,1000);
        LockTimerTask lockTimerTask = new LockTimerTask();
        timer.schedule(lockTimerTask,100,1000);
        //当有一个任务发生异常,后面的所有任务都会被取消,所以一定要在任务重写的run方法内捕获异常
        timer.schedule(myTimerTask,100,1000);
        ExceptionTimerTask exceptionTimerTask = new ExceptionTimerTask();
        timer.schedule(exceptionTimerTask,100,1000);
    }

}

TimerTask 和Timer 的注意点:

(1)Timer调度类内部只有一个线程。内部的队列是基于堆实现的优先级队列。会按照下次执行时间排优先级,但是由于只有一个线程,有时任务会被延迟执行。

(2)固定频率的任务被延迟后,可能会立即执行多次,将次数补够。

(3)固定延时任务的延时相对的时任务执行前的时间,也就是说当上一个任务休眠或者其他原因时,后一个任务会被延时相应的时间。

(4)不可以在任务内部无限循环,会导致后面任务无法执行。

(5)一个定时任务未处理异常就会导致所有任务都被取消。

ScheduledExecutorService:

并发包下的定时任务接口ScheduleExecutorService实现了执行服务接口ExecutorService:它的实现类是scheduledThreadPoolExecutor集成了ThreadPoolExecutor。所以没有了固定频率一下子执行多条的情况第一执行时间是initialDelay后,后面都是加period。而固定延时任务的延时时间也更为合理了,是任务执行之后的时间+period。
同时当一个任务出现异常时也不会影响其他任务,只是发生这个异常的任务被终止。它的任务队列是一个无界的优先级队列,所以做大线程数对它没有作用,即使corePoolSize为0,它也至少有一个线程在运行。

ScheduledThreadPoolExecutor 常用方法:

//单次执行Runnable任务,执行时间是当前时间+delay
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
        if (command != null && unit != null) {
            RunnableScheduledFuture<Void> t = this.decorateTask((Runnable)command, new ScheduledThreadPoolExecutor.ScheduledFutureTask(command, (Object)null, this.triggerTime(delay, unit), sequencer.getAndIncrement()));
            this.delayedExecute(t);
            return t;
        } else {
            throw new NullPointerException();
        }
    }
   //单次执行Callable任务,执行时间是当前时间+delay
    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
        if (callable != null && unit != null) {
            RunnableScheduledFuture<V> t = this.decorateTask((Callable)callable, new ScheduledThreadPoolExecutor.ScheduledFutureTask(callable, this.triggerTime(delay, unit), sequencer.getAndIncrement()));
            this.delayedExecute(t);
            return t;
        } else {
            throw new NullPointerException();
        }
    }
 //固定频率执行任务,第一次执行时间是当前时间+initialDelay,后面每次执行时间是执行任务结束后时间+period  
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
        if (command != null && unit != null) {
            if (period <= 0L) {
                throw new IllegalArgumentException();
            } else {
                ScheduledThreadPoolExecutor.ScheduledFutureTask<Void> sft = new ScheduledThreadPoolExecutor.ScheduledFutureTask(command, (Object)null, this.triggerTime(initialDelay, unit), unit.toNanos(period), sequencer.getAndIncrement());
                RunnableScheduledFuture<Void> t = this.decorateTask((Runnable)command, sft);
                sft.outerTask = t;
                this.delayedExecute(t);
                return t;
            }
        } else {
            throw new NullPointerException();
        }
    }

//固定重复执行任务,第一次执行时间是当前时间+initialDelay,后面每次执行时间是执行任务结束后时间+period  

    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
        if (command != null && unit != null) {
            if (delay <= 0L) {
                throw new IllegalArgumentException();
            } else {
                ScheduledThreadPoolExecutor.ScheduledFutureTask<Void> sft = new ScheduledThreadPoolExecutor.ScheduledFutureTask(command, (Object)null, this.triggerTime(initialDelay, unit), -unit.toNanos(delay), sequencer.getAndIncrement());
                RunnableScheduledFuture<Void> t = this.decorateTask((Runnable)command, sft);
                sft.outerTask = t;
                this.delayedExecute(t);
                return t;
            }
        } else {
            throw new NullPointerException();
        }
    }

Executors工厂类提供的方法:

//单线程的定时任务
 public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
    }
    //单线程的定时任务线程,由自定义线程工厂创建线程
    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
        return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1, threadFactory));
    }

//多线程的定时任务线程,由用户指定线程数
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

//多线程的定时任务线程,由用户指定线程数,由自定义的线程工厂创建线程
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
public class ScheduleExecutorServiceMine {

    static class OrderTimerTask implements Runnable {

        @Override
        public void run() {
            System.out.println("并发定时任务A");
            try {
                Thread.sleep(2000);
            }catch (InterruptedException i){
                i.printStackTrace();
            }
        }
    }

   static class SortTimerTak implements Callable<Integer> {


       @Override
       public Integer call() throws Exception {
           System.out.println("定时任务B");
           return 1;
       }
   }

   static class ExceptionConcurrentTimerTask implements Runnable {

       @Override
       public void run() {
           System.out.println("异常任务");
           throw new RuntimeException();
       }
   }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ScheduledExecutorService scheduleExecutorService =
                (ScheduledExecutorService) new ScheduledThreadPoolExecutor(2);
        OrderTimerTask orderTimerTask = new OrderTimerTask();
        SortTimerTak sortTimerTak = new SortTimerTak();
        //当前时间单次延时执行
        scheduleExecutorService.schedule(orderTimerTask,1000, TimeUnit.MILLISECONDS);
        //返回的ScheduledFuture扩展了异步结果接口Future<V>和Delayed接口
        ScheduledFuture<Integer> future = scheduleExecutorService.schedule(sortTimerTak,1000,TimeUnit.MILLISECONDS);
        System.out.println(future.get());

        ScheduledExecutorService scheduledExecutorService1 = Executors.newScheduledThreadPool(10);
        ExceptionConcurrentTimerTask exceptionTimer = new ExceptionConcurrentTimerTask();
        scheduledExecutorService1.scheduleAtFixedRate(exceptionTimer,1000,1000,TimeUnit.MILLISECONDS);
    }
}

总结:

我们本章节学习了定时任务的基本使用和内部基础原理,TimerTask和Timer并发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值