首页 > 编程语言 >【java】定时器

【java】定时器

时间:2023-05-04 14:12:06浏览次数:48  
标签:定时器 java Timer 任务 long 定时 执行 public

 

定时器的实现方式:

线程等待实现:

最原始最简单的方式,先创建一个thread,然后让它在while循环里一直运行着,通过sleep方法来达到定时任务的效果。

 

public class Task {
    public static void main(String[] args) {
        // run in a second
        final long timeInterval = 1000;
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("Hello !!");
                    try {
                        Thread.sleep(timeInterval);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

 

JDK自带Timer实现:

Timer是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以安排任务“执行一次”或者定期“执行多次”。

// 在指定延迟时间后执行指定的任务

schedule(TimerTask task,long delay);

// 在指定时间执行指定的任务。(只执行一次)

schedule(TimerTask task, Date time);

// 延迟指定时间(delay)之后,开始以指定的间隔(period)重复执行指定的任务

schedule(TimerTask task,long delay,long period);

// 在指定的时间开始按照指定的间隔(period)重复执行指定的任务

schedule(TimerTask task, Date firstTime , long period);

// 在指定的时间开始进行重复的固定速率执行任务

scheduleAtFixedRate(TimerTask task,Date firstTime,long period);

// 在指定的延迟后开始进行重复的固定速率执行任务

scheduleAtFixedRate(TimerTask task,long delay,long period);

// 终止此计时器,丢弃所有当前已安排的任务。

cancal();

// 从此计时器的任务队列中移除所有已取消的任务。

purge();

在指定延迟时间后执行一次,这类是比较常见的场景,比如:当系统初始化某个组件之后,延迟几秒中,然后进行定时任务的执行。

public class DoSomethingTimerTask extends TimerTask {
    private String taskName;
    public DoSomethingTimerTask(String taskName) {
        this.taskName = taskName;
    }
    @Override
    public void run() {
        System.out.println(new Date() + " : 任务「" + taskName + "」被执行。");
    }
}
public class DelayOneDemo {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new DoSomethingTimerTask("DelayOneDemo"),1000L);
    }
}

Timer的缺陷:

Timer计时器可以定时(指定时间执行任务)、延迟(延迟5秒执行任务)、周期性地执行任务(每隔个1秒执行任务)。但是,Timer存在一些缺陷。首先Timer对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。

其次Timer线程是不会捕获异常的,如果TimerTask抛出的了未检查异常则会导致Timer线程终止,同时Timer也不会重新恢复线程的执行,它会错误的认为整个Timer线程都会取消。同时,已经被安排单尚未执行的TimerTask也不会再执行了,新的任务也不能被调度。故如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。

JDK自带ScheduledExecutorService

ScheduledExecutorService是JAVA 1.5后新增的定时任务接口,它是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行。也就是说,任务是并发执行,互不影响。

需要注意:只有当执行调度任务时,ScheduledExecutorService才会真正启动一个线程,其余时间ScheduledExecutorService都是出于轮询任务的状态。

  ScheduledExecutorService主要有以下4个方法:

ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit);

<V> ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);

ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnitunit);

ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnitunit);

  其中scheduleAtFixedRate和scheduleWithFixedDelay在实现定时程序时比较方便,运用的也比较多。

ScheduledExecutorService中定义的这四个接口方法和Timer中对应的方法几乎一样,只不过Timer的scheduled方法需要在外部传入一个TimerTask的抽象任务。

而ScheduledExecutorService封装的更加细致了,传Runnable或Callable内部都会做一层封装,封装一个类似TimerTask的抽象任务类(ScheduledFutureTask)。然后传入线程池,启动线程去执行该任务。

Quartz框架实现

  Quartz是Job scheduling(作业调度)领域的一个开源项目,Quartz既可以单独使用也可以跟spring框架整合使用,在实际开发中一般会使用后者。使用Quartz可以开发一个或者多个定时任务,每个定时任务可以单独指定执行的时间,例如每隔1小时执行一次、每个月第一天上午10点执行一次、每个月最后一天下午5点执行一次等。

   Quartz通常有三部分组成:调度器(Scheduler)、任务(JobDetail)、触发器(Trigger,包括SimpleTrigger和CronTrigger)。下面以具体的实例进行说明。

  要使用Quartz,首先需要在项目的pom文件中引入相应的依赖:

 

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.3.2</version>
</dependency>

 

Spring Task

从Spring 3开始,Spring自带了一套定时任务工具Spring-Task,可以把它看成是一个轻量级的Quartz,使用起来十分简单,除Spring相关的包外不需要额外的包,支持注解和配置文件两种形式。通常情况下在Spring体系内,针对简单的定时任务,可直接使用Spring提供的功能。

基于XML配置文件的形式就不再介绍了,直接看基于注解形式的实现。代码示例:

 

@Component("taskJob")
public class TaskJob {

    @Scheduled(cron = "0 0 3 * * ?")
    public void job1() {
        System.out.println("通过cron定义的定时任务");
    }

    @Scheduled(fixedDelay = 1000L)
    public void job2() {
        System.out.println("通过fixedDelay定义的定时任务");
    }

    @Scheduled(fixedRate = 1000L)
    public void job3() {
        System.out.println("通过fixedRate定义的定时任务");
    }
}

 

  如果是在Spring Boot项目中,需要在启动类上添加@EnableScheduling来开启定时任务。

上述代码中,@Component用于实例化类,这个与定时任务无关。@Scheduled指定该方法是基于定时任务进行执行,具体执行的频次是由cron指定的表达式所决定。关于cron表达式上面CronTrigger所使用的表达式一致。与cron对照的,Spring还提供了fixedDelay和fixedRate两种形式的定时任务执行。

 

fixedDelay和fixedRate的区别

fixedDelay和fixedRate的区别于Timer中的区别很相似。

fixedRate有一个时刻表的概念,在任务启动时,T1、T2、T3就已经排好了执行的时刻,比如1分、2分、3分,当T1的执行时间大于1分钟时,就会造成T2晚点,当T1执行完时T2立即执行。

fixedDelay比较简单,表示上个任务结束,到下个任务开始的时间间隔。无论任务执行花费多少时间,两个任务间的间隔始终是一致的。

 

Spring 中,定时任务接口 SchedulingConfigurer

Spring 中,创建定时任务除了使用@Scheduled 注解外,还可以使用 SchedulingConfigurer。

@Schedule 注解有一个缺点,其定时的时间不能动态的改变,而基于 SchedulingConfigurer 接口的方式可以做到。SchedulingConfigurer 接口可以实现在@Configuration 类上,同时不要忘了,还需要@EnableScheduling 注解的支持。

该接口的实现方法如下:

public void configureTasks(ScheduledTaskRegistrar taskRegistrar)

其中 ScheduledTaskRegistrar 类的方法有下列几种:

从方法的命名上可以猜到,方法包含定时任务,延时任务,基于 Cron 表达式的任务,以及 Trigger 触发的任务。

下面演示了使用方法。

import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
@EnableScheduling
public class SpringSchedulingConfigurerTest01 implements SchedulingConfigurer {


    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        // 默认的,SchedulingConfigurer 使用的也是单线程的方式,如果需要配置多线程,则需要指定 PoolSize
//        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
//        taskScheduler.setPoolSize(10);
//        taskScheduler.initialize();
//        taskRegistrar.setTaskScheduler(taskScheduler);

        taskRegistrar.addFixedRateTask(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行定时任务1: " + new Date());
            }
        }, 1000);

        TriggerTask triggrtTask = new TriggerTask(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行定时任务2: " + new Date());
            }
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                // 返回执行周期(Date),cron表达式
                return new CronTrigger("0/2 * * * * ?").nextExecutionTime(triggerContext);
            }
        });
        taskRegistrar.addTriggerTask(triggrtTask);
    }
    
}

 

 

 

参考:Spring 中,定时任务接口 SchedulingConfigurer - 腾讯云开发者社区-腾讯云 (tencent.com)

 

 

 

 

 

 

1、线程等待实现:

先从最原始最简单的方式来讲解。可以先创建一个thread,然后让它在while循环里一直运行着,通过sleep方法来达到定时任务的效果。

标签:定时器,java,Timer,任务,long,定时,执行,public
From: https://www.cnblogs.com/ryxxtd/p/17371056.html

相关文章

  • [Javascript] Proxy - Snippets
    Blog:https://dev.to/marclipovsky/discovering-the-power-of-javascript-proxy-after-all-this-time-4627 Lazyloading:constlazyLoadHandler={get:function(target,property){if(!target[property]){target[property]=expensiveComputation(......
  • 2-BS结构的系统通信原理(没有涉及到Java小程序)
    1.WEB系统的访问过程第一步:打开浏览器第二步:找到地址栏第三步:输入一个合法的网址第四步:回车第五步:在浏览器上会展示响应的结果。2.关于域名:https://www.baidu.com/(网址)www.baidu.com是一个域名在浏览器地址栏上输入域名,回车之后,域名解析器会将域名解析出来一个具......
  • 查看Java进程启动的详细参数
    问题解决分析和定位一个Java线上系统问题,我们需要查看JVM启动时的一些参数设置,例如:垃圾回收算法、堆大小等等。这些参数可能在启动脚本中明确指明,也可能采用默认值。在系统运行过程中其他人也许动态调整了系统参数。通过jps命令找对对应的pid进程号[root@swk-207~]#ps-ef|......
  • 【访问者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现
    简介访问者模式(VisitorPattern)是一种行为型模式。它封装一个访问者类,把各元素类的操作集合起来,目的是将数据结构与数据操作分离。在不改变原有元素类数据结构的前提下,改变了元素类的执行算法。当某些较为稳定的东西(数据结构或算法),不想直接被改变但又想扩展功能,这时候适合用访问......
  • 毕业生进入社会,JAVA工程师面试经验汇总
    Java工程师是高度需求的技术岗位之一,面试过程非常重要。以下是一些Java工程师面试经验:基础知识:面试官可能会问关于Java基础知识的问题,例如Java语言特性、集合框架、多线程等。在准备面试时,应该学习这些内容,并确保自己能回答相关问题。经验和项目:面试官通常会问你参与的项目和你遇......
  • Java中 HTTP下载 常用的需要设置的MIME类型
    .docapplication/msword.dotapplication/msword.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document.dotxapplication/vnd.openxmlformats-officedocument.wordprocessingml.template.docmapplication/vnd.ms-wo......
  • Java中进行高精准度坐标数据计算使用BigDecimal(计算距离、开平方)
    场景Java中使用java.awt.geom.Point2D进行坐标相关的计算(距离、平方等):https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/126072919Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等):https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article......
  • java 数组操作
    去重List<PolicySalaryVO>policySalaryVO=policySalaryDTOList.stream().map(PolicySalaryVO::new).collect(Collectors.collectingAndThen(Collectors.toCollection(()->newTreeSet<>(Comparator.comparing(PolicySalaryVO::getType))),ArrayList::new))......
  • java-高精确处理常用的数学运算
     用于高精确处理常用的数学运算packagecom.vivo.ars.util;importjava.math.BigDecimal;/***用于高精确处理常用的数学运算*/publicclassArithmeticUtils{//默认除法运算精度privatestaticfinalintDEF_DIV_SCALE=10;/***提供精确的......
  • java基于springboot+vue非前后端分离的网上商城购物系统、在线商城管理系统,附源码+数
    1、项目介绍java基于springboot+vue非前后端分离的网上商城购物系统、在线商城管理系统,实现管理员:首页、个人中心、用户管理、商品分类管理、商品信息管理、订单评价管理、系统管理、订单管理,用户;首页、个人中心、订单评价管理、我的收藏管理、订单管理,前台首页;首页、商品信息、......