java Timer(定时调用、实现固定时间执行)
最近需要用到定时调用的功能。可以通过java的Timer类来进行定时调用,下面是有关Timer的一些相关知识。
其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了run方法的一个类,而具体的TimerTask需要由你自己来实现,例如这样:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
System.out.println("11232");
}
}, 200000 , 1000);
在说到timer的原理时,我们先看看Timer里面的一些常见方法:
1、这个方法是调度一个task,经过delay(ms)后开始进行调度,仅仅调度一次。
public void schedule(TimerTask task, long delay)
2、在指定的时间点time上调度一次。
public void schedule(TimerTask task, Date time)
public void schedule(TimerTask task, long delay, long period)
public void schedule(TimerTask task, Date firstTime, long period)
public void scheduleAtFixedRate(TimerTask task, long delay, long period)
public void scheduleAtFixedRate(TimerTask task, Date firstTime,long period)
public Timer() {
this("Timer-" + serialNumber());
}
创建的线程不为主线程,则主线程结束后,timer自动结束,而无需使用cancel来完成对timer的结束。
public Timer(boolean isDaemon) {
this("Timer-" + serialNumber(), isDaemon);
}
另外两个构造方法负责传入名称和将timer启动:
public Timer(String name, boolean isDaemon) {
thread.setName(name);
thread.setDaemon(isDaemon);
thread.start();
}
这里有一个thread,这个thread很明显是一个线程,被包装在了Timer类中,我们看下这个thread的定义是:
private TimerThread thread = new TimerThread(queue);
而定义TimerThread部分的是:
看到这里知道了,Timer内部包装了一个线程,用来做独立于外部线程的调度,而TimerThread是一个default类型的,默认情况下是引用不到的,是被Timer自己所使用的。
private TaskQueue queue = new TaskQueue();
看名字就知道是一个队列,队列里面可以先猜猜看是什么,那么大概应该是我要调度的任务吧,先记录下了,接下来继续向下看:
来看下方法:
public void schedule(TimerTask task, long delay)
的源码如下:
public void schedule(TimerTask task, long delay) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
这里调用了另一个方法,将task传入,第一个参数传入System.currentTimeMillis()+delay可见为第一次需要执行的时间的 时间点了(如果传入Date,就是对象.getTime()即可,所以传入Date的几个方法就不用多说了),而第三个参数传入了0,这里可以猜下要么是 时间片,要么是次数啥的,不过等会就知道是什么了;另外关于方法:sched的内容我们不着急去看他,先看下重载的方法中是如何做的
public void schedule(TimerTask task, long delay,long period)
源码为:
public void schedule(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, -period);
}
看来也调用了方法sched来完成调度,和上面的方法唯一的调度时候的区别是增加了传入的period,而第一个传入的是0,所以确定这个参数为时间片, 而不是次数,注意这个里的period加了一个负数,也就是取反,也就是我们开始传入1000,在调用sched的时候会变成-1000,其实最终阅读完 源码后你会发现这个算是老外对于一种数字的理解,而并非有什么特殊的意义,所以阅读源码的时候也有这些困难所在。
public void scheduleAtFixedRate(TimerTasktask,long delay,long period)
源码为:
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, period);
}
唯一的区别就是在period没有取反,其实你最终阅读完源码,上面的取反没有什么特殊的意义,老外不想增加一个参数来表示 scheduleAtFixedRate,而scheduleAtFixedRate和schedule的大部分逻辑代码一致,因此用了参数的范围来作为 区分方法,也就是当你传入的参数不是正数的时候,你调用schedule方法正好是得到scheduleAtFixedRate的功能,而调用 scheduleAtFixedRate方法的时候得到的正好是schedule方法的功能,呵呵,这些讨论没什么意义,讨论实质和重点:
来看sched方法的实现体:
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
queue为一个队列,我们先不看他数据结构,看到他在做这个操作的时候,发生了同步,所以在timer级别,这个是线程安全的,最后将task相关的参数赋值,主要包含nextExecutionTime(下一次执行时间),period(时间片),state(状态),然后将它放入queue队列中,做一次notify操作,为什么要做notify操作呢?看了后面的代码你就知道了。
简言之,这里就是讲task放入队列queue的过程,此时,你可能对queue的结构有些兴趣,那么我们先来看看queue属性的结构TaskQueue:
class TaskQueue {
private TimerTask[] queue = new TimerTask[128];
private int size = 0;
可见,TaskQueue的结构很简单,为一个数组,加一个size,有点像ArrayList,是不是长度就128呢,当然不 是,ArrayList可以扩容,它可以,只是会造成内存拷贝而已,所以一个Timer来讲,只要内部的task个数不超过128是不会造成扩容的;内部 提供了add(TimerTask)、size()、getMin()、get(int)、removeMin()、quickRemove(int)、 rescheduleMin(long newTime)、isEmpty()、clear()、fixUp()、fixDown()、heapify();
public class MyTask extends TimerTask
{ @Override
public void run()
{
SimpleDateFormat sdf = null;
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println("当前时间:" + sdf.format(new Date())); } }
public class TestTask
{
public static void main(String[] args)
{
Timer t = new Timer(); // 建立Timer对象
MyTask task = new MyTask(); //定义任务
t.schedule(task, 1000,2000);//设置任务的执行,1秒后开始,每2秒执行一次 Calendar cal = Calendar.getInstance();
cal.set(Calendar.MINUTE, 30); t.schedule(task, cal.getTime() , 2000); }
}
2、通过匿名内部类实现
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() { System.out.println("abc");
}
}, 1000 , 1000);
致谢:感谢您的耐心阅读!
java Timer(定时调用、实现固定时间执行)的更多相关文章
- java Timer 定时每天凌晨1点执行任务
import java.util.TimerTask;/** * 执行内容 * @author admin_Hzw * */public class Task extends TimerTask { ...
- java Timer 定时每天凌晨0点执行任务
import java.util.TimerTask; /** * 执行内容 * @author admin_Hzw * */ public class Task extends TimerTask ...
- C#固定时间执行指定事件(观察者模式+异步委托)
最近有个项目需要每天固定的时间去执行指定的事件,发现网上关于这样的文章比较少,而且比较散.通过学习了几篇文章后终于实现了这个功能,在此也特别感谢这些文章的作者们,这也是我第一次在园子里面发文章,望多指 ...
- timer和ScheduledThreadPoolExecutor定时任务和每日固定时间执行
//ScheduledThreadPoolExecutor每三秒执行一次 public static void main(String[] args) { ScheduledThread ...
- Timer定时方法(间隔时间后执行)
Timer time = new Timer(); time.schedule(new TimerTask() { @Override public void run() { // TODO Auto ...
- Java Timer定时器时,每次重复执行了两次任务的解决方案
web.xml监听配置 com.numenzq.mc.service.impl.TimerListener TimerListener类 public class TimerListener impl ...
- 如何在JAVA中每隔一段时间执行一段程序
可以用线程来做,每隔几秒开一个线程代码如下 public void runTask() { final long timeInterval = 120000;// 两分钟运行一次 final Thre ...
- 测试使用Timer定时调用http接口
转自:https://blog.csdn.net/qq_36004521/article/details/80101881
- java中定时执行任务
现在项目中用到需要定时去检查文件是否更新的功能.timer正好用于此处. 用法很简单,new一个timer,然后写一个timertask的子类即可. 代码如下: package comz.autoup ...
随机推荐
- oracle的minus返回第一个表中有、第二个表中没有的数据
oracle的minus返回第一个表中有.第二个表中没有的数据 CREATE TABLE hovertree_union_1 ( id INT, val ) ); CREATE TABLE hover ...
- (Python学习4)List对象
1.PyListObject对象 typedef struct { PyObject_VAR_HEAD PyObject **ob_item; Py_ssize_t allocated; } PyLi ...
- (转载)IO-同步、异步、阻塞、非阻塞
一.概述 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不 ...
- 基于吉日嘎底层架构的Web端权限管理操作演示-用户管理
相信博客园的朋友对吉日嘎拉都不陌生,相信很多人也买了他的源码,应用于自己的项目. 但是你有没有过一个困惑? 那就是:没有一个基于网页的权限管理界面. 今天,这一切都不再是问题,我花了3年时间研究学习并 ...
- 关于IIS寄宿WCF服务,客户端不能生成代理类
我在使用VS2010写好WCF的Web服务后,部署在IIS7.0上,可以在IE9上进行访问,并且能显示XML数据,如下图 然后我在项目的客户端进行服务的添加引用,如下图 VS2010自动生成代理类,但 ...
- 泛函编程(23)-泛函数据类型-Monad
简单来说:Monad就是泛函编程中最概括通用的数据模型(高阶数据类型).它不但涵盖了所有基础类型(primitive types)的泛函行为及操作,而且任何高阶类或者自定义类一旦具备Monad特性就可 ...
- If you insist running as root, then set the environment variable RUN_AS_USER=root...
版权声明:本文为博主原创文章,不经博主允许注明链接即可转载. If you insist running as root, then set theenvironment variable RUN_A ...
- 关于SQL Server的WITH(NOLOCK)和(NOLOCK)
The difference is that you should be using the syntax WITH (NOLOCK) (or WITH (<any table hint> ...
- 以Self Host的方式来寄宿Web API
Common类及实体定义.Web API的定义请参见我的上一篇文章:以Web Host的方式来寄宿Web API. 一.以Self Host寄宿需要新建一个Console控制台项目(SelfHost) ...
- JSON数据解析(转)
上篇随笔详细介绍了三种解析服务器端传过来的xml数据格式,而对于服务器端来说,返回给客户端的数据格式一般分为html.xml和json这三种格式,那么本篇随笔将讲解一下json这个知识点,包括如何通过 ...