当前位置:首页 > java知识学习_java技术文章 > 正文

多种java时间定时器实现方式 time和线程对比

浏览264+

一、java中的定时器介绍

何为定时器呢?定时器就好比我们的闹铃一样,当我们设置好了固定的时间之后到期就会自动按照我们的意愿做某些事情完成某个功能和任务,java中提供了很多可供我们实现定时器的技术比如:time就是jdk自带的定时器类,此外还有很多用java语言编写的定时器框架完美整合spring框架,比如:QuartZ定时任务框架等,在实际的工作中也是比较常用的。

二、多种java定时器实现详解与代码编写

time类定时器:

开篇介绍过,time是java提供的用于完成相关定时任务的jdk类,此种方式主要用到time和timeTask两个相关类,timeTask是定时任务类,主要负责编写定时器的业务逻辑,time类负责设置定时时间执行timeTask的业务逻辑,下面这张类图可以清晰的展示二者之间的关系。

time和timeTask类图

timeTask的使用时需要我们自己编写一个类,然后继承TimeTask类,重写run()方法,run()方法里面定义需要做的业务逻辑,具体代码如下:

public class MyTask  extends TimerTask{

@Override

public void run() {

System.out.println(“开始运行”);

}

time类可以直接new创建对象,然后调用schedule方法执行业务逻辑,代码如下:

public class TimeTest {

public static void main(String[] args) {

Timer timer = new Timer();

timer.schedule(new MyTask(),1000,2000);

}

schedule的几个传入参数我们有必要细讲一下,因为这几个参数定义了定时的时间,参数格式如下:timer.schedule(TimerTask, 0, 60 * 60 * 1000),TimerTask参数值的是上面的业务逻辑类,0指的是执行等待时间,表示间隔多少秒之后开始执行,此处设置为0表示不等待,60 * 60 * 1000表示间隔时间,意思是每间隔1小时执行一次该任务。

需要注意的是如果第三个参数传入的是个Date类型的日期的话,则会到达该日期的时间事执行。

time时间定时器类的实现原理:

在jdk1.3中启动了time,通过使用TimerTask数组作为队列,将所有定时任务添加到队列中, 然后它启动一个线程,该线程在队列为空时阻塞,并删除TimerTask以确定队列中是否有数据,是否是时候运行任务,并且如果运行时间小于或等于当前时间,则任务开始运行。

quartz  java框架时间定时器:

quartz是一个定时任务框架也叫作业调度框架,完全由java语言开发而来并且是开源的,既能够单独应用也能够结合javaEE的Spring框架整合使用,也是定时任务的常用利器,并且比time类更加强大。

Quartz使用一种可配置的方法,其中所有计时器都在XML文件中配置, 常规步骤如下:
1.创建一个spring配置文件:spring-quartz.xml。
2.定义工作任务的工作,代码如下:

工作任务代码

3.定义触发器并将其绑定到作业,代码如下:

触发器与job绑定的代码

4.定义调度程序,并向调度程序注册触发器,代码如下:

<!– 3.定义调度器,并将trigger注册进去 –>
<bean name=”quartzScheduler” class=”org.springframework.scheduling.quartz.SchedulerFactoryBean”>
<property name=”triggers”>
<list>
<ref local=”testJobTrigger” />
</list>
</property>
</bean>

quartz与spring整合做时间定时器的完整代码

ScheduledExecutorService线程池实现java定时器:

ExecutorService是java并发包下Executor的子类,其下又有两个衍生的很重要的两个子类,分别是ThreadPoolExecutor和ScheduledExecutorService,ThreadPoolExecutor就是并发编程中创建各式各样线程池的类,这里暂且不做过多介绍,我们主要介绍ScheduledExecutorService,该接口定义了线程池和周期性任务执行的功能,刚好可以实现定时器的功能。

ScheduledExecutorService接口中总共定义了四个执行任务的方法,见下图:

ScheduledExecutorService接口中的方法

scheduleAtFixedRate方法参数详解:

scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);

第一个参数command定义了具体的执行任务,第二个参数initialDelay定义了初始化后该方法第一次执行的周期时间,第三个参数period定义了周期性执行任务的间隔时间,第四个参数unit定义的时间单位。

当第一次执行任务完成的时间小于间隔时间的话,则会等待时间到达后再次执行,当执行任务完成的时间大于间隔时间则会直接执行下次任务。

scheduleWithFixedDelay方法参数详解:

scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);

第一个参数同上,第二个参数给定initialDelay时间延迟后,任务开始,任务完成后,再等待第三个参数delay延迟时间以再次执行任务,因为它等待任务完成,然后再延迟delay个时间,所以它不会受到任务何时完成以及完成时间的影响。

以下是scheduleAtFixedRate方法实现线程池定时器的代码:

线程池定时器代码

三、time和ScheduledExecutorService线程池定时器优缺点比较

time是单线程执行任务,只有一个线程工作,当同时有多个任务需要执行时未免有些自顾不暇,处理延时任务有一定的缺陷,当任务执行时间过长时只能执行完一个再去执行另一个。

time对异常处理不够完善,如果执行任务过程中抛出了InterruptedException异常,time会终止任务的执行,从而导致后序的任何任务都不能执行,见下图异常测试用例:

time对异常处理

综上所述,time确实不适合同时执行多个定时任务,当一个任务延迟时会将延迟时间不断累加到其它任务中去,因此time做任务的调度还是不错的,将任务调度到其它外部准备的线程池中去运行也是不错的选择。

ScheduledExecutorService是对time缺陷的升级,完全可以取代time,自带线程池,可以同时启动多个线程并行的执行多个任务,对第一次任务执行的时间和间隔时间也可以灵活设置。

 

相关文章推荐

quartz定时任务时间设置

Java中Timer定时器是怎么写

java定时器 每天12点 固定执行一个方法

java定时器-Timer和TimerTask详解

java—定时器的实现

java定时器(spring框架内置的定时器)

Java 定时任务实现原理详解

JAVA实现定时器的四种方式

jdk自带定时器使用方法详解

JFinal – scheduler 插件做定时任务