返回顶部
首页 > 资讯 > 后端开发 > Python >Java Timer使用讲解
  • 148
分享到

Java Timer使用讲解

Java Timer使用Java Timer 2022-11-13 19:11:22 148人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录Timer 详解定时功能一、一次性任务二、可重复执行任务三、固定延时和固定速率区别(重点)1. 介绍2. 固定速率3. 固定延时4. 其他要点四、调度多个TimerTa

Timer 详解

Timer 和 TimerTask 用于在后台线程中调度任务的 java.util 类。 TimerTask 负责任务的执行, Timer 负责任务的调度。

定时功能

Timer 提供了三种定时模式:

fixed delay
fixed rate

java.util包下提供了对定时任务的支持,涉及2个类:

  1. Timer:定时器类
  2. TimerTask:任务抽象类

使用该定时任务我们需要继承TimerTask抽象类,覆盖run方法编写任务执行代码,并利用Timer定时器对TimerTask进行调度。

编写一个任务:

TimerTask task = new TimerTask() {
    @Override
    public void run() {
        System.out.println(DateUtil.fORMatNow() + " " + Thread.currentThread().getName() + " task run ");
    }
};

接着使用Timer对TimerTask进行调度,Timer提供了多种方法,可分为一次性任务和可重复执行任务。

一、一次性任务

一次性任务是指Timer执行一次之后,该任务后续不再执行。

一次性任务包括2个方法,如下:

  1. voidschedule(TimerTasktask,longdelay):延迟delay毫秒后执行一次task
  2. voidschedule(TimerTasktask,Datetime):在指定时间time执行一次task,如果time过期,将会立即执行

二、可重复执行任务

可重复执行任务是指,任务允许按照设定的规则重复执行。

可重复执行任务共有4个方法,分为固定延时 schedule和固定速率 scheduleAtFixedRate:

  1. voidschedule(TimerTasktask,longdelay,longperiod):延迟delay毫秒后执行task,之后每隔period毫秒执行一次task
  2. voidschedule(TimerTasktask,DatefirstTime,longperiod):在指定时间time执行一次task,之后每隔period毫秒执行一次task
  3. voidscheduleAtFixedRate(TimerTasktask,longdelay,longperiod):延迟delay毫秒后执行task,之后每隔period毫秒执行一次task
  4. voidscheduleAtFixedRate(TimerTasktask,DatefirstTime,longperiod):在指定时间time执行一次task,之后每隔period毫秒执行一次task

示例1:schedule方法,延迟delay毫秒后执行task,之后每隔period毫秒执行一次task

System.out.println("启动于:" + DateUtil.formatNow());
Timer timer = new Timer("timer");
timer.schedule(task, 1000, 2000);

输出:

启动于:2022-10-31 10:05:15
2022-10-31 10:05:16 timer task run 
2022-10-31 10:05:18 timer task run 
2022-10-31 10:05:20 timer task run

示例2:schedule在指定时间time执行一次task,之后每隔period毫秒执行一次task

System.out.println("启动于:" + DateUtil.formatNow());
Timer timer = new Timer("timer");
timer.schedule(task, DateUtil.parse("2022-10-31 10:07:00", DateUtil.YYYY_MM_DD_HH24_MM_SS), 2000);

输出:

启动于:2022-10-31 10:06:39
2022-10-31 10:07:00 timer task run 
2022-10-31 10:07:02 timer task run 
2022-10-31 10:07:04 timer task run 

固定延时 schedule 和 固定速率 scheduleAtFixedRate 在正常情况下看起来功能基本是一致的,区别在于当任务耗时超出执行时间间隔period,后续任务被延误时,schedule和scheduleAtFixedRate的处理方式不同,后面介绍。

三、固定延时和固定速率区别(重点)

1. 介绍

由于Timer内部仅维护一个线程来执行所有任务,所以当前一个任务耗时过长,可能会导致后一个任务的执行被延误。

出现任务延误的情况下,固定延时 schedule和 固定速率 scheduleAtFixedRate 的区别就在于,schedule会顺延,而scheduleAtFixedRate会把延误任务立马补上。

在网上看到几个非常恰当的例子,贴上来加深理解。

例1:

暑假到了老师给schedule和scheduleAtFixedRate两个同学布置作业。

老师要求学生暑假每天写2页,30天后完成作业。

这两个学生每天按时完成作业,直到第10天,出了意外,两个学生出去旅游花了5天时间,这5天时间里两个人都没有做作业。任务被拖延了。

这时候两个学生采取的策略就不同了:

schedule重新安排了任务时间,旅游回来的第一天做第11天的任务,第二天做第12天的任务,最后完成任务花了35天。

scheduleAtFixedRate是个守时的学生,她总想按时完成老师的任务,于是在旅游回来的第一天把之前5天欠下的任务以及第16天当天的任务全部完成了,之后还是按照老师的原安排完成作业,最后完成任务花了30天。

例2:

固定速率就好比你今天加班到很晚,但是到了第二天还必须准点到公司上班,如果你一不小心加班到了第二天早上 9 点,你就连休息的时间都没有了。

而固定时延的意思是你必须睡够 8 个小时再过来上班,如果你加班到凌晨 6 点,那就可以下午过来上班了。

固定速率强调准点,固定时延强调间隔。

如果任务必须每天准点调度,那就应该使用固定速率调度,并且要确保每个任务执行时间不要太长,避免超过period间隔。

如果任务需要每隔几分钟跑一次,那就使用固定时延调度,它不是很在乎单个任务要跑多长时间。

我们来模拟一下这个情况。

首先,我们对TimerTask进行修改,让它某一次任务产生大量耗时:

TimerTask task = new TimerTask() {
    private int i = 1;
    @Override
    public void run() {
        System.out.print(i + " " + DateUtil.formatNow() + " 开始执行, ");
        if(i == 3) {
            ThreadUtil.sleep(11 * 1000);
        }
        System.out.println(DateUtil.formatNow() + " 结束");
        i++;
    }
};

该任务在执行第3次时,将会休眠11秒,这将会导致延误后续的任务。

2. 固定速率

示例:

Timer timer = new Timer("timer");
timer.scheduleAtFixedRate(task, 5000, 2000);

设定任务延迟5秒后执行第1次任务,之后每2秒执行一次。

输出:

启动于:2022-10-31 15:51:24
1 2022-10-31 15:51:29 开始执行, 2022-10-31 15:51:29 结束
2 2022-10-31 15:51:31 开始执行, 2022-10-31 15:51:31 结束
3 2022-10-31 15:51:33 开始执行, 2022-10-31 15:51:44 结束 *
4 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *
5 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *
6 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *
7 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *
8 2022-10-31 15:51:44 开始执行, 2022-10-31 15:51:44 结束 *
9 2022-10-31 15:51:45 开始执行, 2022-10-31 15:51:45 结束
10 2022-10-31 15:51:47 开始执行, 2022-10-31 15:51:47 结束
11 2022-10-31 15:51:49 开始执行, 2022-10-31 15:51:49 结束

如果不存在第3次耗时11秒的情况下,正常任务执行时间应该为:

启动于:2022-10-31 15:51:24
1 2022-10-31 15:51:29 开始执行, 2022-10-31 15:51:29 结束
2 2022-10-31 15:51:31 开始执行, 2022-10-31 15:51:31 结束
3 2022-10-31 15:51:33 开始执行, 2022-10-31 15:51:33 结束 *
4 2022-10-31 15:51:35 开始执行, 2022-10-31 15:51:35 结束 *
5 2022-10-31 15:51:37 开始执行, 2022-10-31 15:51:37 结束 *
6 2022-10-31 15:51:39 开始执行, 2022-10-31 15:51:39 结束 *
7 2022-10-31 15:51:41 开始执行, 2022-10-31 15:51:41 结束 *
8 2022-10-31 15:51:43 开始执行, 2022-10-31 15:51:43 结束 *
9 2022-10-31 15:51:45 开始执行, 2022-10-31 15:51:45 结束
10 2022-10-31 15:51:47 开始执行, 2022-10-31 15:51:47 结束
11 2022-10-31 15:51:49 开始执行, 2022-10-31 15:51:49 结束

但是在第3次执行任务时因为执行耗时11秒,第4次本该在15:51:35开始执行并完成任务,却到了15:51:44才执行完成,这11秒延误了后续5个任务的正常执行,因此在15:51:44时,scheduleAtFixedRate赶作业把延误的5个任务一起执行了。

最后赶上了原本的进度,第9个任务准时在15:51:45执行。

3. 固定延时

示例:

Timer timer = new Timer("timer");
timer.schedule(task, 5000, 2000);

输出:

启动于:2022-10-31 15:56:59
1 2022-10-31 15:57:04 开始执行, 2022-10-31 15:57:04 结束
2 2022-10-31 15:57:06 开始执行, 2022-10-31 15:57:06 结束
3 2022-10-31 15:57:08 开始执行, 2022-10-31 15:57:19 结束 *
4 2022-10-31 15:57:19 开始执行, 2022-10-31 15:57:19 结束
5 2022-10-31 15:57:21 开始执行, 2022-10-31 15:57:21 结束
6 2022-10-31 15:57:24 开始执行, 2022-10-31 15:57:24 结束
7 2022-10-31 15:57:26 开始执行, 2022-10-31 15:57:26 结束
8 2022-10-31 15:57:28 开始执行, 2022-10-31 15:57:28 结束
9 2022-10-31 15:57:30 开始执行, 2022-10-31 15:57:30 结束
10 2022-10-31 15:57:32 开始执行, 2022-10-31 15:57:32 结束

如果不存在第3次耗时11秒的情况下,正常任务执行时间应该为:

启动于:2022-10-31 15:56:59
1 2022-10-31 15:57:04 开始执行, 2022-10-31 15:57:04 结束
2 2022-10-31 15:57:06 开始执行, 2022-10-31 15:57:06 结束
3 2022-10-31 15:57:08 开始执行, 2022-10-31 15:57:08 结束 *
4 2022-10-31 15:57:10 开始执行, 2022-10-31 15:57:10 结束
5 2022-10-31 15:57:12 开始执行, 2022-10-31 15:57:12 结束
6 2022-10-31 15:57:14 开始执行, 2022-10-31 15:57:14 结束
7 2022-10-31 15:57:16 开始执行, 2022-10-31 15:57:16 结束
8 2022-10-31 15:57:18 开始执行, 2022-10-31 15:57:18 结束
9 2022-10-31 15:57:20 开始执行, 2022-10-31 15:57:20 结束
10 2022-10-31 15:57:22 开始执行, 2022-10-31 15:57:22 结束

使用schedule调度,第4次任务本该在15:57:10开始执行,但由于耗时11秒直到15:57:19才开始。

而第3次任务实际是在19秒完成,完成后又在19秒立即执行第4次,中间少了2秒间隔,第4次完成后接着开始2秒一次,变为了从21秒开始执行第5次。

和我原本的推测不一样的是,本以为19秒完成后,第4次会隔2秒在21秒执行,没想到19秒会立即执行。

猜测与delay参数有关,但调整了delay后仍然一样,完成的那一秒还是会马上再执行第4次任务。

通过以上测试对比,我们可以感受到Timer中固定速率和固定延时的区别,但为了避免出错,使用Timer时应让TimerTask耗时尽可能短。

4. 其他要点

1.以上是仅第3次任务加上了耗时11秒,如果是所有任务都耗时11秒呢?

如果每次任务执行都耗时11秒,那么无论是固定速率还是固定延时,都将是11秒执行一个任务。

2.如果改为schedule(TimerTasktask,DatefirstTime,longperiod)和scheduleAtFixedRate(TimerTasktask,DatefirstTime,longperiod)来调度任务,firstTime指定为10点,而当前系统时间为11点,会出现什么情况呢?

虽然firstTime已经过期,但是Timer将会立即开始执行任务,之后按照period间隔重复执行任务。

3.如果TimerTask执行过程中抛出了异常会发生什么事情?

Timer内部仅维护一个线程,当任一TimerTask抛出异常,将导致此线程终止运行,该Timer负责的所有任务都无法执行。

四、调度多个TimerTask

在上一节中,介绍的是一个可重复执行的TimeTask,如果执行耗时大于设定的间隔period,将会影响该TimerTask下一次执行的时间点。

而这一节则是为了单独说明,一个Timer同时调度多个TimeTask也会互相影响。

示例:

TimerTask task1 = new TimerTask() {
    private int i = 1;
    @Override
    public void run() {
        System.out.print(i + " task1:" + DateUtil.formatNow() + " 开始执行, ");
        ThreadUtil.sleep(11 * 1000);
        System.out.println(DateUtil.formatNow() + " 结束");
        i++;
    }
};
TimerTask task2 = new TimerTask() {
    private int i = 1;
    @Override
    public void run() {
        System.out.print(i + "  task2:" + DateUtil.formatNow() + " 开始执行, ");
        ThreadUtil.sleep(11 * 1000);
        System.out.println(DateUtil.formatNow() + " 结束");
        i++;
    }
};

Timer timer = new Timer("timer");
timer.scheduleAtFixedRate(task1, 5000, 2000);
timer.scheduleAtFixedRate(task2, 5000, 2000);

输出:

1 task1:2022-10-31 16:58:27 开始执行, 2022-10-31 16:58:38 结束
1 task2:2022-10-31 16:58:38 开始执行, 2022-10-31 16:58:49 结束
2 task2:2022-10-31 16:58:49 开始执行, 2022-10-31 16:59:00 结束
2 task1:2022-10-31 16:59:00 开始执行, 2022-10-31 16:59:11 结束
3 task1:2022-10-31 16:59:11 开始执行, 2022-10-31 16:59:22 结束
3 task2:2022-10-31 16:59:22 开始执行, 2022-10-31 16:59:33 结束
4 task2:2022-10-31 16:59:33 开始执行, 2022-10-31 16:59:44 结束
4 task1:2022-10-31 16:59:44 开始执行, 2022-10-31 16:59:55 结束

可以发现,task1和task2其实都没有按照既定时间去执行任务了。

根本原因是在于,Timer内部仅维护一个线程执行所有TimerTask,为了避免错误,一个Timer对象最好仅调度一个TimerTask对象,除非可以确保多个TimerTask之间一定不会相互影响。

因此编写TimerTask时应当自行捕获异常。

五、取消任务

Timer在创建时实际上是默认在内部维护了一个非守护线程,即使任务全部执行完成,线程也并不会销毁。

Timer提供cancel()方法,可以手动调用取消定时器所有的任务,并销毁定时器。

如果想要Timer内部创建的是守护线程,可以使用以下构造方法创建定时器,设置isDaemon为true:

  • Timer(booleanisDaemon)

Timer(Stringname,booleanisDaemon)

如果没有自己定义name参数,默认Timer内部自动命名为“Timer-递增序号”,作为内部线程的线程名称,在构造方法内启动此线程。

如果是要取消单个任务,可以使用TimerTask的cancel()方法。

当TimerTask调用cancel之后,任务是取消了,但Timer自身并不能马上知道TimerTask被取消,而是在准备执行前才知道,因此Timer内部还维护着这个任务的引用。若希望Timer立即清除引用,可调用Timer.purge()立即执行清除。

到此这篇关于Java Timer使用讲解的文章就介绍到这了,更多相关Java Timer使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java Timer使用讲解

本文链接: https://lsjlt.com/news/170585.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java Timer使用讲解
    目录Timer 详解定时功能一、一次性任务二、可重复执行任务三、固定延时和固定速率区别(重点)1. 介绍2. 固定速率3. 固定延时4. 其他要点四、调度多个TimerTa...
    99+
    2022-11-13
    Java Timer使用 Java Timer
  • Java JDBC使用入门讲解
    目录1、JDBC概述1.1、JDBC的概念1.2、JDBC的本质1.3、JDBC的好处2、JDBC快速入门2.1、编写代码2.2、完整案例前言:本节我们开始学习JDBC,JDBC的基...
    99+
    2022-12-08
    Java JDBC Java JDBC是什么
  • java中Unsafe的使用讲解
    目录1.获取unsafe2.获取unsafe前段时间因为看JUC的源码,里面有大量关于unsafe的操作,所以就来看看了.写点笔记总结下(本文基于jdk1.8): unsafe可以帮...
    99+
    2024-04-02
  • 如何在Java中使用Timer定时器
    如何在Java中使用Timer定时器?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、概念      定时计划任务功能在J...
    99+
    2023-05-30
    java timer
  • Java深入讲解SPI的使用
    目录什么是Java SPIJava SPI使用demoSPI在JDBC中的应用SPI在sharding-jdbc中的应用扩展什么是Java SPI   &ensp...
    99+
    2024-04-02
  • Java实例讲解Comparator的使用
    目录前言关于Comparator原题前言 今天刷个题,遇到一个很有趣的问题,关于Comparator的使用,感觉也是一个关于写代码的一些小细节的问题 关于Comparator Com...
    99+
    2022-11-13
    Java Comparator方法 Java Comparator接口
  • Java中的定时器Timer详解
    目录总结简单来说,定时器就相当于一个“闹钟”,给定时器设定一个任务,约定这个任务在xxx时间之后执行~ Timer类提供了一个核心接口,schedule(安排) 指定一个任...
    99+
    2024-04-02
  • C# Timer控件学习之使用Timer解决按钮幂等性问题
    目录前言:Timer控件的属性Timer控件的方法界面设计效果演示代码逻辑总结前言: Timer是一个定时器,作为C#开发Timer控件是我们用的比较多的一个控件,它的功能很简单,但...
    99+
    2022-11-13
    C#timer控件 c# 按钮幂等性
  • 详解推荐使用systemd timer替代cronjob
    目录概述系统自带的 timer创建 timerSystemd timer 时间精度Timer 类型Calendar event 定义测试 calendar 定义总结概述 前几天在使用...
    99+
    2023-05-14
    systemd timer替代cronjob systemd timer
  • 在java项目中如何使用Timer定时器
    在java项目中如何使用Timer定时器?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。定时的功能我们在手机上见得比较多,比如定时清理垃圾,闹钟,等等.定时功能在...
    99+
    2023-05-31
    java 定时器 timer
  • C++中timer如何使用
    这篇文章给大家介绍C++中timer如何使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C++ timer代码示例:/this code is writen by c...
    99+
    2023-06-17
  • Java 超基础讲解String的使用
    目录1.String概述2.特点3.String构造方法4.String对象的特点5.字符串的比较6.实现用户登录7.总结1.String概述 String类在java.lang包下...
    99+
    2024-04-02
  • java SelectableChannel的使实例用法讲解
    1、说明 (1)SelectableChannel 是一个抽象类,它实现了 Channel 接口,这个类比较特殊。 (2)SelectableChannel 可以被 Selector...
    99+
    2024-04-02
  • Java中classpath讲解及使用方式
    笔者之前对于classpath都没有什么深入的研究,之前的项目打包jar包都是按照网上的教程自己照着葫芦画瓢。但是因为最近碰到一些关于这方面的知识,因此索性觉得要好好补充一下这方面的...
    99+
    2024-04-02
  • Java使用elasticsearch基础API使用案例讲解
    1.依赖 我用的是 springboot 2.2.5.RELEASE 版本,这里只贴出主要依赖: <dependency> <groupId>o...
    99+
    2024-04-02
  • Java注解简介和使用详细讲解
    目录注解注解基本介绍自定义注解元注解注解解析注解 注解基本介绍 注解概述: Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Jav...
    99+
    2023-02-28
    Java注解使用 Java注解简介
  • java中Timer定时器怎么用
    小编给大家分享一下java中Timer定时器怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Timer定时器的使用和启动1.概述定时计划任务功能在Java中主...
    99+
    2023-06-22
  • java定时器timer的使用方法代码示例
     1.首先肯定是容器一启动就要启动定时器,所以我们可以选择把定时器写在一个监听器里,容器一启动所以监听器也就跟着启动,然后定时器就可以工作了。第一步,把自己写的监听器加到web.xml中;第二步,写一个监听器,实现ServletC...
    99+
    2023-05-30
    java timer 定时器
  • 一文带你搞懂Java定时器Timer的使用
    目录一、定时器是什么二、自定义定时器一、定时器是什么 定时器类似于我们生活中的闹钟,可以设定一个时间来提醒我们。 而定时器是指定一个时间去执行一个任务,让程序去代替人工准时操作。 标...
    99+
    2023-01-09
    Java定时器Timer使用 Java定时器Timer Java定时器 Java Timer
  • java中Timer定时器的使用和启动方式
    目录Timer定时器的使用和启动1.概述2.应用场景3.使用方法4.启动方法java的几种定时器小结1.@Scheduled注解2.quartz3.使用Timer4.使用线程控制Ti...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作