定时任务简单来说就是在指定时间,指定的频率来执行一个方法,而在 Java 中我们又该如何实现呢?

想来主要有 3 种方式,最原始的方式肯定是开启一个线程,让它睡一会跑一次睡一会跑一次这也就达到了定频率的执行 run 方法,我们只需要将业务逻辑写在 run 方法中即可。这种方式总结就是单个线程来执行单个任务。

方式一:创建一个线程

package com.yu.task;

import java.util.Date;

public class ThreadTest {

    public static void main(String[] args) {
// 设置执行周期
final long timeInterval = 3000; Runnable runnable = new Runnable() {
public void run() {
while (true) {
System.out.println("Task Run ... " + new Date()); try {
Thread.sleep(timeInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
}

第二种方式:使用 JDK 自带的 API Timer 以及 TaskTimer。

这种方式和第一种简单粗暴的方式有什么区别呢,主要体现在使用 API 可以在指定的时间开始启动任务,可以延期执行首次任务,同样也看可以设置一定的时间间隔,但是原理是是一样的,后台还是启动了一个线程,应该说是只有一个线程在执行任务,不管我们启动的 Task 有几个。所以这也会有问题,比方说一个一个任务没有执行完成,另一个任务就开始执行了,可能会发生并发问题。还有若是一个任务中报错,则线程就会被停止。

package com.yu.task;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class MyTask extends TimerTask{ private String name; public MyTask(String name) {
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public void run() {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sf.format(new Date());
System.out.println("exec MyTask ... 当前时间为:" + format);
System.out.println(this.name +" 正在执行!" + sf.format(new Date()));
} public static void main(String[] args) {
Timer timer = new Timer();
TimerTask task1 = new MyTask("Tasks 1");
TimerTask task2 = new MyTask("Tasks 2"); Calendar calendar1 = Calendar.getInstance();
calendar1.add(Calendar.SECOND, 3);
Calendar calendar2 = Calendar.getInstance();
calendar2.add(Calendar.SECOND, 5); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sf.format(new Date());
System.out.println("当前时间为:" + format); timer.schedule(task1, calendar1.getTime(), 3000L);
timer.schedule(task2, calendar2.getTime(), 3000L);
} }

其实在 Timer 中,封装了一个 Task 的队列和 Time 的线程对象,我们自定义的 Task 的引用会放在队列中等待执行。

大致是这么一个关系 Timer -  TimerThread - TaskQueue - MyTask - run  当然最终执行的方法肯定是我们自定义任务中的 run 方法。因为我们自定义的任务已经继承了 TimeTask ,而这个类已经实现了 Runnable 接口。

Timer 定时器第一种方式好的地方还在于可以选择关闭任务,查看任务的执行情况等。下面介绍几个相关的方法。

启动定时任务也有几个不同的方法,每个都有不同的使用场景。

上面是 Timer 类中的属性和方法的简图,开启一个任务我们主要使用 6 个方法, 一共 3 组,先看简单的

schedule() 方法中含有两个参数,主要是用来执行一次任务的,不存在频率的问题,而 3 个参数表示执行什么任务,什么时候开始执行/延时多久执行,多久执行一次。

现在来假设一个场景,01秒开始执行一个任务,频率是 3 秒执行一次,不知道你们有没有想到这个情况,若是这个方法本身执行需要 4 秒,那第二次执行的时间是 04 呢? 还是 05 秒呢?

而这个差别就是 schedule 和 scheduleAtFixedRate 方法的区别,前者会按照任务执行的情况来执行下一次任务,也就是说 01 之后,会等第一次执行结束再开始第二次,这样就会带来一个问题,每次执行时间都比预想的要晚。而 scheduleAtFixedRate 则不存在这个问题,它会按照指定的时间和频率执行,这样坐就会出现,同一时刻会有两个任务在同时执行,若是,可能会发生并发问题。

上面讨论的是当任务本身执行的时间大于频率时,两个方法不同的执行情况,还有一个情况,若是当前时间晚于我们设定的开始执行时间又会怎么办呢?

schedule () 会比较符合正常思维,晚了就晚了,现在开始执行就是,不存在补回的情况,但是 scheduleAtFixedRate 则会一次性补回未执行的次数。举例来说,当前时间为 09,而我们设定的开始时间为 00 ,频率为 3 秒,则 schedule 会在 09 执行一次,12 执行一次。而 scheduleAtFixedRate 会在 09 一次性执行 4 次,12 执行一次,后面就是正常的频率。

下面再说几个可能会起到锦上添花作用的方法,我们的若是想取消任务的执行,有一个方法但是分为两个类执行,我们可以调用 TimeTask 中的 cancel 方法,这个方法只对当前任务有效,若是想取消全部的任务,则需要调用 Timer 中的 cancel 方法。

那有该如何查看定时器 Timer 中已经被取消任务的数量呢?当然还是有方法的,那就是 Timer 中的 purge 方法。

说了这么说,实际上我们可以看到,Timer 定时器本身还是调用线程来完成定时操作。且后台只有一个多线程 TimeThread 在工作。

那 Timer 定时器有什么缺点呢?

1 并发操作时的缺陷,这是因为 Timer 的后台只有一个执行线程导致的,容易引起并发问题。

2 任务抛出异常时缺陷。如果 TimeTask 抛出 RuntimeException,Timer 会停止所有任务的执行。

所以以后我们在使用 Timer 定时器的时候要注意,这两个情况,多任务且并发执行的时候不要使用 Timer,复杂任务调度的时候也不要使用 Timer ,因为一个不小心出现异常了,所有任务都卡壳了。但是,Timer 定时器处理一些简单的定是任务还是非常方便的!比方说我想实现的,定时发送邮件。用起来就很是方便,因为这是 JDK 自带的 API 呀!

第三种方式:使用 Java 中的专门用于定时任务管理的框架 Quartz 。(还没学,等等吧……)

上面也说了 Timer 定时器的弊端,怎么办,据听说 Quartz 可以解决这些……

后记:据我知道,Java 中定时任务也就这几个吧,欢迎补充,有好多人说到某某框架中有定时任务,我想说的是,那不是!那是框架集成了上面说的定时任务框架,可能集成的就是 Quartz,或是 Quartz 的简化版本……

Java 中的定时任务(一)的更多相关文章

  1. 转:java中的定时任务

    引自:http://www.cnblogs.com/wenbronk/p/6433178.html java中的定时任务, 使用java实现有3种方式: 1, 使用普通thread实现 @Test p ...

  2. Java中的定时任务

    现代的应用程序早已不是以前的那些由简单的增删改查拼凑而成的程序了,高复杂性早已是标配,而任务的定时调度与执行也是对程序的基本要求了. 很多业务需求的实现都离不开定时任务,例如,每月一号,移动将清空你上 ...

  3. java中实现定时任务 task 或quartz

    转载大神的 https://www.cnblogs.com/hafiz/p/6159106.html https://www.cnblogs.com/luchangyou/p/6856725.html ...

  4. java中的定时任务小示例

    package package_1; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; ...

  5. java中实现定时功能

    网上资料: 我们可以使用Timer和TimerTask类在java中实现定时任务,详细说明如下: 1.基础知识java.util.Timer一种线程设施,用于安排以后在后台线程中执行的任务.可安排任务 ...

  6. java中基于TaskEngine类封装实现定时任务

    主要包括如下几个类: 文章标题:java中基于TaskEngine类封装实现定时任务 文章地址: http://blog.csdn.net/5iasp/article/details/10950529 ...

  7. 在Java Web项目中添加定时任务

    在Java Web程序中加入定时任务,这里介绍两种方式:1.使用监听器注入:2.使用Spring注解@Scheduled注入. 推荐使用第二种形式. 一.使用监听器注入 ①:创建监听器类: impor ...

  8. 如何用 Java 实现 Web 应用中的定时任务?

    定时任务,是指定一个未来的时间范围执行一定任务的功能.在当前WEB应用中,多数应用都具备任务调度功能,针对不同的语音,不同的操作系统, 都有其自己的语法及解决方案,windows操作系统把它叫做任务计 ...

  9. 如何用 Java 实现 Web 应用中的定时任务

    定时任务,是指定一个未来的时间范围执行一定任务的功能.在当前WEB应用中,多数应用都具备任务调度功能,针对不同的语音,不同的操作系统, 都有其自己的语法及解决方案,windows操作系统把它叫做任务计 ...

随机推荐

  1. OAuth2:Authorization Flows

    Ref:http://www.dannysite.com/blog/176/ OAuth2.0协议定义了用于获得授权的四种主要授权类型. 1. Client Credentials 一种基于APP的密 ...

  2. SpringBoot 线程池配置 实现AsyncConfigurer接口方法

      目的是:  通过实现AsyncConfigurer自定义线程池,包含异常处理  实现AsyncConfigurer接口对异常线程池更加细粒度的控制 *a) 创建线程自己的线程池  b) 对void ...

  3. react-music React全家桶项目,精品之作!

    React-Music 全家桶项目,精品之作! 一.简介 该项目是基于React全家桶开发的一个音乐播放器,技术栈采用:Webpack + React + React-redux + React-ro ...

  4. ASP.NET配置文件Web.config 详细解释

    一.认识Web.config文件 Web.config文件是一个XML文本文件,它用来储存 ASP.NET Web 应用程序的配置信息(如最常用的设置ASP.NET Web 应用程序的身份验证方式), ...

  5. TIP协议

    1. TIP是什么? CISCO给TIP的定义如下: The TIP protocol specifications describe how to multiplex multiple screen ...

  6. HDU 1556 Color the ball (树状数组 区间更新+单点查询)

    题目链接 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽&quo ...

  7. Python概念-反射之文化底蕴版:反正射了

    什么是反射 光在两种物质分界面上改变传播方向又返回原来物质中的现象,叫反射! 以上,是反射的物理定义,与python中的反射概念,完全没有任何关系 书归正传:反射 就是通过字符串的形式,操作对象相关的 ...

  8. 【译】第五篇 Integration Services:增量加载-Deleting Rows

    本篇文章是Integration Services系列的第五篇,详细内容请参考原文. 在上一篇你学习了如何将更新从源传送到目标.你同样学习了使用基于集合的更新优化这项功能.回顾增量加载记住,在SSIS ...

  9. 003_Mac挂载NTFS移动硬盘读取VMware虚拟机文件

    一.Mac 挂载NTFS移动硬盘进行读写操作 (Read-only file system) 注意如下图所示先卸载,然后按照下图的命令进行挂载.然后cd /opt/003_vm/   &&am ...

  10. python 之sqlite3库学习

    # -*- coding:utf-8 -*- # 导入SQLite驱动:>>> import sqlite3# 连接到SQLite数据库# 数据库文件是test.db# 如果文件不存 ...