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 ...
随机推荐
- 【C#】OOP之继承那点事
前言: 继承这点事,说多不多,说少不少,这里只描述了一些我认为的基础篇,望各位大神指教.本节参照了C#高级编程和Think in java对继承的描述,我个人认为OOP只是思想,故看明白一个就说通的, ...
- windbg学习进阶之——dump分析常用命令收集
#重要说明 (1) windbg命令分为标准命令,元命令和扩展命令. 标准命令提供最基本的调试功能,不区分大小写.如:bp g dt dv k等 元命令提供标准命令没有提供的功能,也内建在调试 ...
- 泛函编程(14)-try to map them all
虽然明白泛函编程风格中最重要的就是对一个管子里的元素进行操作.这个管子就是这么一个东西:F[A],我们说F是一个针对元素A的高阶类型,其实F就是一个装载A类型元素的管子,A类型是相对低阶,或者说是基础 ...
- Liunx目录结构
/bin: bin是Binary的缩写, 这个目录存放着最经常使用的命令. /boot:这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件. /dev :dev是Device ...
- springMVC图片文件上传功能的实现
在工程依赖库下添加文件上传jar包 commons-fileupload-1.2.2.jar commons-io-2.4.jar 2.jsp页面设置form表单属性enctype 在表单中上传图片时 ...
- gulp小记(无刷新重载样式)
之前在使用sass的时候,使用了一个不错的工具koala,其实它的原理就是监视sass文件的变化,去编译css而gulp也能为我们做这样的事并且更多 使用gulp之前我们要做一些准备工作 1)安装no ...
- JavaScript hasOwnProperty() 函数详解
hasOwnProperty()函数用于指示一个对象自身(不包括原型链)是否具有指定名称的属性.如果有,返回true,否则返回false. 该方法属于Object对象,由于所有的对象都"继承 ...
- miniSipServer简单而不简单,轻松落地,实现电脑对固话、手机通讯
最近沉迷于SIP通讯,网内通讯全免费,落地也就几分钱,而且无漫游全国拨打,想想真是心动呢,只要有网落就ok!. 对于sipserver,现在的市场上软件很多,免费的.收费的应有尽有,这里不一一例举.综 ...
- 读取XML绑定TreeNode
<asp:TreeView ID="treeview" OnClick="TreeViewCheckBox_Click()" runat="se ...
- GitHub 基本常用知识解答2
1.如何拥有一个Git仓库的两种途径 (1)在已有的目录中,初始化一个新的. (2) 比如一个新的项目,或者一个已存在的项目,但该项目尚未有版本控制.如果你想要复制一份别人的项目, 或者与别人合作某个 ...