Java中JDK定时任务

news2024/11/15 8:37:58

Java中JDK定时任务

  • 一、JDK自带Timer
    • 1.Timer核心方法
      • (1)schedule与scheduleAtFixedRate区别
        • schedule侧重保持间隔时间的稳定
        • scheduleAtFixedRate保持执行频率的稳定
    • 2.java.util.TimerTask
      • (1)TimerTask核心方法
    • 3.Timer的缺陷
    • 4.Timer使用示例
      • (1)指定延迟执行一次
      • (2)固定间隔执行
      • (3)固定速率执行
  • 二、JDK自带ScheduledExecutorService
    • 1.ScheduledExecutorService核心方法
    • 2.ScheduledExecutorService使用示例
      • (1)scheduleWithFixedDelay
      • (2)scheduleAtFixedRate


一、JDK自带Timer

  • 参考官方文档 ===> Timer - Java 11 中文版 - API 参考文档
  • java.util.Timer 线程的工具,用于在后台线程中安排将来执行的任务。 可以将任务安排为一次性执行,或者以固定间隔重复执行
  • 对应于每个Timer对象的是一个后台线程,用于按顺序执行所有计时器的任务。 计时器任务应该快速完成。 如果计时器任务需要花费过多的时间来完成,它会“占用”计时器的任务执行线程。 反过来,这可以延迟后续任务的执行,后续任务可以在紧急任务最终完成时(以及如果)快速连续地“聚集”并执行。
  • 在对Timer对象的最后一次实时引用消失并且所有未完成的任务都已完成执行之后,计时器的任务执行线程正常终止(并且变为垃圾回收)。 但是,这可能需要很长时间才能发生。默认情况下,任务执行线程不作为守护程序线程运行,因此它能够阻止应用程序终止。如果调用者想要快速终止计时器的任务执行线程,则调用者应该调用计时器的cancel方法。
  • 此类是线程安全的:多个线程可以共享单个Timer对象,而无需外部同步。

1.Timer核心方法

  • java.util.Timer 类的核心方法如下:
    void cancel()	//终止此计时器,丢弃当前计划的任何任务。
    int	purge()	//从此计时器的任务队列中删除所有已取消的任务。
    void schedule​(TimerTask task, long delay)	//在指定的延迟后安排指定的任务执行。
    void schedule​(TimerTask task, long delay, long period)	//在指定的延迟之后开始,为重复的固定延迟执行安排指定的任务。
    void schedule​(TimerTask task, Date time)	//计划在指定时间执行指定的任务。
    void schedule​(TimerTask task, Date firstTime, long period)	//从指定时间开始,为重复的固定延迟执行安排指定的任务。
    void scheduleAtFixedRate​(TimerTask task, long delay, long period)	//在指定的延迟之后开始,为重复的固定速率执行安排指定的任务。
    void scheduleAtFixedRate​(TimerTask task, Date firstTime, long period)  //从指定时间开始,为重复的 固定速率执行安排指定的任务。
    

(1)schedule与scheduleAtFixedRate区别

  • 在了解schedulescheduleAtFixedRate方法的区别之前,先看看它们的相同点:
    • 任务执行未超时,下次执行时间 = 上次执行开始时间 + period;
    • 任务执行超时,下次执行时间 = 上次执行结束时间;
    • 在任务执行未超时时,它们都是上次执行时间加上间隔时间,来执行下一次任务。而执行超时时,都是立马执行。
  • 它们的不同点在于侧重点不同,schedule方法侧重保持间隔时间的稳定,而scheduleAtFixedRate方法更加侧重于保持执行频率的稳定
schedule侧重保持间隔时间的稳定
  • schedule方法会因为前一个任务的延迟而导致其后面的定时任务延时。计算公式为scheduledExecutionTime(第n+1次) = realExecutionTime(第n次) + periodTime。
  • 也就是说如果第n次执行task时,由于某种原因这次执行时间过长,执行完后的systemCurrentTime>= scheduledExecutionTime(第n+1次)则此时不做时隔等待,立即执行第n+1次task
  • 而接下来的第n+2次task的scheduledExecutionTime(第n+2次)就随着变成了realExecutionTime(第n+1次)+periodTime。这个方法更注重保持间隔时间的稳定。
scheduleAtFixedRate保持执行频率的稳定
  • scheduleAtFixedRate在反复执行一个task的计划时,每一次执行这个task的计划执行时间在最初就被定下来了,也就是scheduledExecutionTime(第n次)=firstExecuteTime +n*periodTime
  • 如果第n次执行task时,由于某种原因这次执行时间过长,执行完后的systemCurrentTime>= scheduledExecutionTime(第n+1次),则此时不做period间隔等待,立即执行第n+1次task。
  • 接下来的第n+2次的task的scheduledExecutionTime(第n+2次)依然还是firstExecuteTime+(n+2)*periodTime这在第一次执行task就定下来了。说白了,这个方法更注重保持执行频率的稳定。

如果用一句话来描述任务执行超时之后schedule和scheduleAtFixedRate的区别就是:schedule的策略是错过了就错过了,后续按照新的节奏来走;scheduleAtFixedRate的策略是如果错过了,就努力追上原来的节奏(制定好的节奏)。

2.java.util.TimerTask

  • 参考官方文档 === > TimerTask - Java 11 中文版 - API 参考文档

  • java.util.TimerTask 可由java.util.Timer一次性或重复执行的任务 。

  • 计时器任务不可重复使用。 一旦任务被安排在Timer上执行或被取消,后续尝试安排执行将抛出IllegalStateException

    package java.util;
    
    public abstract class TimerTask implements Runnable {
        /**
         * This object is used to control access to the TimerTask internals.
         */
        final Object lock = new Object();
    
        /**
         * The state of this task, chosen from the constants below.
         */
        int state = VIRGIN;
    
        /**
         * This task has not yet been scheduled.
         */
        static final int VIRGIN = 0;
    
        /**
         * This task is scheduled for execution.  If it is a non-repeating task,
         * it has not yet been executed.
         */
        static final int SCHEDULED   = 1;
    
        /**
         * This non-repeating task has already executed (or is currently
         * executing) and has not been cancelled.
         */
        static final int EXECUTED    = 2;
    
        /**
         * This task has been cancelled (with a call to TimerTask.cancel).
         */
        static final int CANCELLED   = 3;
        long nextExecutionTime;
        long period = 0;
    
        protected TimerTask() {
        }
    
        public abstract void run();
    
        public boolean cancel() {
            synchronized(lock) {
                boolean result = (state == SCHEDULED);
                state = CANCELLED;
                return result;
            }
        }
        
        public long scheduledExecutionTime() {
            synchronized(lock) {
                return (period < 0 ? nextExecutionTime + period
                                   : nextExecutionTime - period);
            }
        }
    }
    

(1)TimerTask核心方法

  • java.util.TimerTask 类的核心方法如下:
    boolean	cancel()	//取消此计时器任务。
    abstract void run()	//此计时器任务要执行的操作。
    long scheduledExecutionTime()	//返回此任务最近 实际执行的 计划执行时间。
    

3.Timer的缺陷

  • Timer计时器可以定时(指定时间执行任务)、延迟(延迟5秒执行任务)、周期性地执行任务(每隔个1秒执行任务)。但是,Timer存在一些缺陷。
    • 首先Timer对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。
    • 其次Timer线程是不会捕获异常的,如果TimerTask抛出的了未检查异常则会导致Timer线程终止,同时Timer也不会重新恢复线程的执行,它会错误的认为整个Timer线程都会取消。同时,已经被安排但尚未执行的TimerTask也不会再执行了,新的任务也不能被调度。故如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。由于 Timer 底层是单线程

4.Timer使用示例

(1)指定延迟执行一次

  • 在指定延迟时间后执行一次,这类是比较常见的场景,比如:当系统初始化某个组件之后,延迟几秒中,然后进行定时任务的执行。
    public class TestTimer {
        public static void main(String[] args) {
            Timer timer = new Timer();
    
            //定时任务启动
            System.out.println(new Date() + "定时任务开始");
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000L);//模拟执行任务花费的时间
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(new Date() + "---任务执行完成");
                }
            }, 2000L);
        }
    }
    
    在这里插入图片描述

(2)固定间隔执行

  • 在指定的时间开始执行定时任务,定时任务按照固定的间隔进行执行。比如:程序开始运行就执行,固定执行间隔为2秒。

    public class TestTimer {
        public static void main(String[] args) {
            Timer timer = new Timer();
            timer.schedule(new TimerTaskImpl(),new Date(), 2000L);
        }
    }
    class TimerTaskImpl extends TimerTask {
    
        private boolean test = true;
    
        @Override
        public void run() {
            System.out.println(new Date() + "---定时任务开始");
            if(test) {
                try {
                    Thread.sleep(3000L);//模拟执行任务花费的时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(new Date() + "---任务执行完成");
                test = !test;
            }
            else {
                try {
                    Thread.sleep(1000L);//模拟执行任务花费的时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(new Date() + "---任务执行完成");
            }
        }
    }
    

    在这里插入图片描述

(3)固定速率执行

  • 在指定的时间开始执行定时任务,定时任务按照固定的速率进行执行。比如:程序开始运行就执行,固定执行速率为2秒。

    public class TestTimer {
        public static void main(String[] args) {
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTaskImpl(),new Date(), 2000L);
        }
    }
    class TimerTaskImpl extends TimerTask {
    
        private boolean test = true;
    
        @Override
        public void run() {
            System.out.println(new Date() + "---定时任务开始");
            if(test) {
                try {
                    Thread.sleep(3000L);//模拟执行任务花费的时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(new Date() + "---任务执行完成");
                test = !test;
            }
            else {
                try {
                    Thread.sleep(1000L);//模拟执行任务花费的时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(new Date() + "---任务执行完成");
            }
        }
    }
    

    在这里插入图片描述


二、JDK自带ScheduledExecutorService

  • ScheduledExecutorService - Java 11中文版 - API参考文档
  • ScheduledExecutorService 解决了 Timer 的缺陷问题。
  • ScheduledExecutorService是JAVA 1.5后新增的定时任务接口,它是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行。也就是说,任务是并发执行,互不影响。
  • 需要注意:只有当执行调度任务时,ScheduledExecutorService才会真正启动一个线程,其余时间ScheduledExecutorService都是处于轮询任务的状态。

1.ScheduledExecutorService核心方法

  • ScheduledExecutorService主要有以下4个方法:

    // 提交在给定延迟后启用的一次性任务。
    ScheduledFuture<?>	schedule​(Runnable command,
     							 long delay,
     							 TimeUnit unit)	
    //提交一个返回值的一次性任务,该任务在给定的延迟后变为启用状态。
    <V> ScheduledFuture<V>	schedule​(Callable<V> callable,
    								 long delay,
    								 TimeUnit unit)	
    //提交定期操作,该操作在给定的初始延迟后首先启用,随后在给定的时间段内启用; 也就是说,执行将在initialDelay之后开始,然后是initialDelay + period ,然后是initialDelay + 2 * period ,依此类推。
    ScheduledFuture<?>	scheduleAtFixedRate​(Runnable command, //command为被执行的线程
    										long initialDelay, //initialDelay为初始化后延时执行时间
    										long period, //period为两次开始执行最小间隔时间
    										TimeUnit unit) //unit为计时单位
    //提交在给定的初始延迟之后首先启用的定期动作,并且随后在一次执行的终止和下一次执行的开始之间给定延迟。
    ScheduledFuture<?>	scheduleWithFixedDelay​(Runnable command, //command为被执行的线程
    										   long initialDelay, //initialDelay为初始化后延时执行时间
    										   long delay, //delay为前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)
    										   TimeUnit unit) //unit为计时单位。	
    
    • ScheduledExecutorService中定义的这四个接口方法和Timer中对应的方法几乎一样,只不过Timerscheduled方法需要在外部传入一个TimerTask的抽象任务。而ScheduledExecutorService封装的更加细致了,传RunnableCallable内部都会做一层封装,封装一个类似TimerTask的抽象任务类(ScheduledFutureTask)。然后传入线程池,启动线程去执行该任务。

2.ScheduledExecutorService使用示例

(1)scheduleWithFixedDelay

  • scheduleWithFixedDelay是不管任务执行多久,都会等上一次任务执行完毕后再延迟delay后去执行下次任务。
    public class ScheduleWithFixedDelay implements Runnable{
        public static void main(String[] args) {
            ScheduledExecutorService executor = Executors.newScheduledThreadPool(15); //设置线程数
            executor.scheduleWithFixedDelay(
                    new ScheduleWithFixedDelay(),
                    0,
                    2000,
                    TimeUnit.MILLISECONDS);
        }
    
        @Override
        public void run() {
            System.out.println(new Date() + "  " + Thread.currentThread() +" : 任务「ScheduleWithFixedDelay」被执行。");
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    在这里插入图片描述

(2)scheduleAtFixedRate

  • scheduleAtFixedRate是以period为间隔来执行任务的,如果任务执行时间小于period,则上次任务执行完成后会间隔period后再去执行下一次任务;但如果任务执行时间大于period,则上次任务执行完毕后会不间隔立即开始下次任务

    public class ScheduleAtFixedRate implements Runnable {
        public static void main(String[] args) {
            ScheduledExecutorService executor = Executors.newScheduledThreadPool(13);
            executor.scheduleAtFixedRate(
                    new ScheduleAtFixedRate(),
                    0,
                    1000,
                    TimeUnit.MILLISECONDS);
        }
    
        @Override
        public void run() {
            System.out.println(new Date() + " " + Thread.currentThread() + ": 任务「ScheduleAtFixedRate」被执行。");
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

    在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1510457.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内部审计2.0时代:数字化工具和方法全面升级

文章目录 一、内部审计的发展阶段二、内部审计的逻辑架构三、内部审计数字化转型面临的问题&#xff08;1&#xff09;缺少内部审计数字化转型规划和方案&#xff08;2&#xff09;非结构化数据的采集和后续利用不足&#xff08;3&#xff09;依赖编程或使用新工具的数据分析能…

MySQL分析sql语句的性能瓶颈的几种方式介绍

在 MySQL 中&#xff0c;性能瓶颈可能会导致数据库系统运行缓慢&#xff0c;影响用户体验。为了确保数据库的性能&#xff0c;识别和解决性能瓶颈是非常重要的。以下是一些常用的方法来分析 SQL 语句的性能瓶颈&#xff1a; 1. EXPLAIN 语句 EXPLAIN 是一个强大的工具&#xff…

发布DDD脚手架到Maven仓库,IntelliJ IDEA 配置一下即可使用

这篇文章将帮助粉丝伙伴们更高效地利用小傅哥构建的DDD&#xff08;领域驱动设计&#xff09;脚手架&#xff0c;搭建工程项目&#xff0c;增强使用的便捷性。让&#x1f46c;&#x1f3fb;兄弟们直接在 IntelliJ IDEA 配置个在线的链接&#xff0c;就能直接用上这款脚手架&…

day1-C++

1>提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数要求使用C风格字符串完成。 代码&#xff1a; #include <iostream> #include <string.h> using namespace std;int main() {string str ;int low 0, …

在funtion中用分号间隔还是逗号间隔

问: 回答: 这段代码是一个Vue组件方法的实现&#xff0c;名为resetForm。该方法的主要作用是关闭一个对话框&#xff08;通过设置this.dialogFormVisible false&#xff09;&#xff0c;重置表单字段&#xff08;使用this.$refs[formName].resetFields();&#xff09;&#x…

ROS机器人程序设计课程进度安排-2023-2024-2

进度安排由人工智能审核制定。 课程 教学进度表预期效果与课程内容详细描述 一、预期效果 此教学进度表旨在确保《ROS机器人程序设计》课程在2023&#xff5e;2024学年度第二学期内&#xff0c;按照预定的教学计划和进度&#xff0c;有序、高效地进行。通过本课程的教学&…

容器(0)-DOCKERFILE-安装-常用命令-部署-迁移备份-仓库

1.安装 启动 systemclt start docker //启动 systemctl status docker //状态 docker info systemclt stop docker systemctl status docker systemctl enable docker //开机启动 2.常用命令 镜像查看 docker images 镜像查看 docker status 镜像拉取 docker pull centos:…

【Spring】idea连接mysql数据库

1 MySQL安装 下载地址&#xff1a;https://dev.mysql.com/downloads/installer/ 安装server only选项&#xff0c;之后的可以选择默认安装选项 2 MySQL登录并创建数据 -- 创建数据库 create databases spring_db; use spring_db; -- 创建表 create table users (id INT AUTO…

学习大数据,所需要Java基础(9)

文章目录 网络编程实现简答客户端和服务器端的交互编写客户端编写服务端 文件上传文件上传客户端以及服务器端实现文件上传服务器端实现&#xff08;多线程&#xff09;文件上传服务器端&#xff08;连接池版本&#xff09;关闭资源工具类 BS架构服务器案例案例分析BS结构服务器…

网络请求与数据解析

urllib是Python自带的标准库中用于网络请求的库 &#xff0c;无需安装&#xff0c;直接引用即可。通常用于爬虫开发、API&#xff08;应用程序编程接口&#xff09;数据获取和测试。 urllib库的几个模块&#xff1a; urllib.request :用于打开和读取URLurllib.error:包含提出…

Jenkins插件Parameterized Scheduler用法

Jenkins定时触发构建的同时设定参数。可以根据不同的定时构建器设置不同参数或环境变量的值。可以设置多个参数。并结合when控制stage流程的执行。结合when和triggeredBy区分定时构建的stage和手动执行的stage。 目录 什么是Parameterized Scheduler&#xff1f;如何配置实现呢…

用Origin快速拟合荧光寿命、PL Decay (TRPL)数据分析处理

需要准备材料&#xff1a;Origin、PL Decay数据txt文件 首先打开Origin画图软件 导入数据&#xff0c;按照下图箭头操作直接导入 双击你要导入的PL Decay的txt数据文件&#xff0c;然后点OK 继续点OK 数据导入后首先删除最大光子数之前的无效数据&#xff0c;分析的时候用…

react中的useEffect的使用

目录 React的useEffect深度解析与实战应用 一、useEffect的基本使用 二、useEffect的依赖项数组 三、避免无限循环 四、使用清空函数进行清理 React的useEffect深度解析与实战应用 React Hooks 是 React 16.8 版本引入的新特性&#xff0c;它允许我们在不编写 class 的情况…

AHU 汇编 实验二

一、实验名称&#xff1a;实验二 不同寻址方式的灵活运用 二、实验内容&#xff1a;定义数组a[6]&#xff0c;用多种寻址方式访问对应元素&#xff0c;实现&#xff08;a[0]a[1]&#xff09;*(a[2]-a[3])/a[4],将结果保存在内存a[5]中&#xff0c;用debug查询结果。 实验过程&a…

盘点 gma 中为 栅格数据 设计的切片操作

数据切片是 Python 中非常实用的方法&#xff0c;Numpy、Pandas 等第三方库的切片操作为数据处理提供了不少便利。如果能对栅格/矢量数据进行切片&#xff0c;那会使地理数据处理也变得方便和快捷。 基于此&#xff0c;自 gma 2.0.6.10 开始&#xff0c;gma 针对 打开的栅格数据…

【使用postman测试python接口】

打开python服务 设置postman如下&#xff0c;并发送&#xff1a; postman新建请求设置请求方式为post设置地址、raw、json方式、内容如下 结果&#xff1a; python如下&#xff1a; from flask import Flask, request, jsonifyapp Flask(__name__) # 实例化对象app.route…

酷开科技智慧AI助力酷开系统千屏千面

每台智能电视都有一个专属的操作系统&#xff0c;而酷开系统作为一款基于人工智能技术的智能电视操作系统&#xff0c;深受大众喜爱&#xff0c;其最大的特点就是“千屏千面”。这意味着每一位消费者在使用酷开系统时&#xff0c;通过酷开科技的智慧AI&#xff0c;都能根据自己…

SpringSecurity原理简述

文章目录 0. 简介1. 快速入门1.1 准备工作1.2 引入SpringSecurity 2. 认证2.1 登陆校验流程2.2 原理初探2.2.1 SpringSecurity完整流程2.2.2 认证流程详解 2.3 解决问题2.3.1 思路分析2.3.2 准备工作2.3.3 实现2.3.3.1 数据库校验用户准备工作核心代码实现 2.3.3.2 密码加密存储…

Java this 关键字

**1.上节课学习了Java对象的定义和使用&#xff0c;我们知道了对象是存在堆内存中的&#xff0c;Java要求程序员不能直接操作堆内存&#xff0c;因此出现了引用的概念。引用的实质是一个存放对象地址的局部变量。 定义一个对象的语法&#xff1a; **Student s1 new Student();…

1.Spring核心功能梳理

概述 本篇旨在整体的梳理一下Spring的核心功能,让我们对Spring的整体印象更加具体深刻,为接下来的Spring学习打下基础。 本片主体内容如下: Bean的生命周期依赖注入的实现Bean初始化原理推断构造方法原理AOP的实现这里要说明一下,我们这里说到的Spring,一般指的是Spring F…