Java Timer And TimerTask执行频率 精确认执行问题 本帖最后由 King520754 于 2011-03-27 14:52:01 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 直接把timer设置成24小时的放到初始化里 你这个需要解决的问题称为 time-critical 我们平时所用的JVM无法解决你的这个问题 道理很简单 你觉得timer帮你跑一边 long delayTime = 24*60*60*1000; 的精度有多准。不过有一部分人正奋斗在这个time-critical java中,java有另外一个版本叫做 java real-time system他是一个还没有实用价值的版本。但是在这个版本中可以做到时间的完全精度化 而且 可以使用像 下周3,12天后,这样的时间计量。有兴趣可以看看 http://java.sun.com/javase/technologies/realtime/index.jsp#jsr-001 不过目前没有太大的实用价值 我问题描述出了点问题:请教:如何能让执行的更精确一些. 现在已经有2个问题了. 1.可能会执行任务.--->应该是:一天内可能会执行多次任务. 因为启动时过了指定的时间,就会立即执行. 我现在想到的办法:只有把指定的晚一点.比如指定到23:50分这个样子. 2.下次执行任务时间会被更改.--->任务执行间隔,以上次为准. Timer作为一个属性存在,设置一个相应的set方法如setxxx(Date date) { if (time == null) {...} else {timer.cancel();} timer.schedule(task, date,delayTime); }当重启时,setxxx(new Date()),指定启动时 setxxx(sometime); 如果当天的时间已经过了,而你又不想让定时任务立即执行,可以判断下时间,让它第二天再执行://判断今天的执行时间是否已经过去,如果过去则改为明天if (date.getTime() < System.currentTimeMillis()) { date = new Date(date.getTime() + 24 * 60 * 60 * 1000);}Timer timer = new Timer();if (configSerial()) { timer.schedule(new MyTimerTask(), date, 24 * 60 * 60 * 1000); showRunningDialog(timer);} 定时执行这类任务还是操作系统的强项,应用层没必要关心太多底层时间时区这些细节在Unix上用cronjob,Windows上用at,你的问题可以很容易解决 Java 里面要实现这样的定时任务还有比较麻烦的,不建议自己去实现,把 Quartz 这个框架的 jar 加进来吧。对于你的这个用途,只用 Quartz 就可以了,不需要用什么 Spring 集成的。如果需要自己实的话,可以使用 java.util.concurrent.DelayQueue,这个称为延迟队列,是 Java 集合框架的实现之一。存放进去的对象必须实现 java.util.concurrent.Delayed 和 java.lang.Comparable<T> 接口。在 Delayed 接口实现 public long getDelay(TimeUnit unit) 方法,如果在计算时返回值是小于等于 0 的话,那么在 DelayQueue 中使用 take 方法可以将其取出来。我们可以在第一次往 DelayQueue 塞任务的时候,把下一次要执行的毫秒保存到这个任务对象中去。等时间一到,那 take 由阻塞状态变为运行状态,会将其中超时的对象取出来。取出来之后,计算下一次运行的毫秒数,再将这个对象塞回队列中去,同时在外部还有这个对象的引用,使用 ExecuteService 接口 submit 执行一次。自己要实现这样的任务调度非常麻烦。这个是我写的小例子作为参考(没有使用 ScheduledExecutorService 类)。任务调度时间是每分钟执行一次(为了便利起见,全写在一个 java 文件中了)。import java.util.Calendar;import java.util.concurrent.DelayQueue;import java.util.concurrent.Delayed;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;public class DelayQueueTest { public static void main(String[] args) throws InterruptedException { SchedulerManager manager = new SchedulerManager(); manager.addJob(new EveryMinuteDelay(new MyJob())); manager.start(); printCurrentTime(); sleepMinutes(3); // 休息 3 分钟后关掉 manager.stop(); // 停止工作 printCurrentTime(); } private static void sleepMinutes(long minutes) { try { TimeUnit.MINUTES.sleep(minutes); } catch (InterruptedException e) { e.printStackTrace(); } } private static void printCurrentTime() { System.out.printf("Current: %tF %<tT%n", System.currentTimeMillis()); }}/** * <p>任务调度管理器</p> * * 2010-5-28 下午11:30:20 */class SchedulerManager { private ExecutorService executor; private DelayQueue<JobDelayed> jobs; private Scheduler scheduler; public SchedulerManager() { this(1); } /** * 根据线程池中线程数量构造调度管理器 * @param threadPool */ public SchedulerManager(int threadPool) { this.jobs = new DelayQueue<JobDelayed>(); // 由于调度管理器需要占用一个线程,因此需要加 1 this.executor = Executors.newFixedThreadPool(threadPool + 1); this.scheduler = new Scheduler(this); } /** * <p>添加需要计划的任务</p> * * @param job */ public void addJob(JobDelayed jobDelayed) { jobDelayed.nextTime(); // 计算下一次执行的时间 jobs.put(jobDelayed); // 添加到延迟队列中去 } public void start() { scheduler.start(); // 启动任务调度器 } public void stop() { scheduler.stop(); // 停止任务调度器 } private void execute() throws InterruptedException { submit(take()); } /** * <p>将任务提交给线程池去执行</p> * * @param task */ private void submit(Runnable task) { executor.submit(task); } /** * <p>强制停止工作</p> */ private void shutdown() { executor.shutdown(); } /** * <p>获取到时间的任务,如果该任务下一次还需要执行,将该任务加回队列中去。</p> * * @return * @throws InterruptedException */ private JobDelayed take() throws InterruptedException { JobDelayed jobDelayed = jobs.take(); if(jobDelayed.hasNext()) { addJob(jobDelayed); } return jobDelayed; } /** * <p>调度器</p> * 2010-5-28 下午11:40:58 */ private static class Scheduler implements Runnable { private SchedulerManager manager; private boolean running = false; /** * 使用调度管理器构造 * @param manager */ public Scheduler(SchedulerManager manager) { this.manager = manager; } /** * <p>启动该调度器</p> */ public void start() { if(!running) { manager.submit(this); this.running = true; } } /** * 执行任务调度工作 */ @Override public void run() { while(running) { try { manager.execute(); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * <p>强制停止该调度器</p> */ public void stop() { manager.shutdown(); running = false; } }}/** * <p>需要进行任务调度的工作内容</p> */interface Job { public void execute();}/** * <p>测试工作,输出当前时间</p> */class MyJob implements Job { public void execute() { System.out.printf("JOB OUTPUT: %tF %<tT%n", System.currentTimeMillis()); }}/** * <p>需要进行调度工作的任务</p> */interface JobDelayed extends Delayed, Runnable { /** * <p>计算下一次执行的时间</p> */ public void nextTime(); /** * <p>下一次是否需要执行</p> */ public boolean hasNext();}/** * <p>需要进行每分钟调度工作的任务</p> */class EveryMinuteDelay implements JobDelayed { private long nextTime; private Job job; public EveryMinuteDelay(Job job) { this.job = job; } public void nextTime() { Calendar c = Calendar.getInstance(); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); c.add(Calendar.MINUTE, 1); this.nextTime = c.getTimeInMillis(); // 这个任务的 nextTime 为下一分钟 } public boolean hasNext() { return true; // 永远执行下去 } @Override public long getDelay(TimeUnit unit) { return nextTime - System.currentTimeMillis(); // 是否超时 } @Override public int compareTo(Delayed o) { return (int)(o.getDelay(TimeUnit.MILLISECONDS) - getDelay(TimeUnit.MILLISECONDS)); } @Override public void run() { job.execute(); // 执行任务 } public String toString() { return String.format("next: %tF %<tT", nextTime); }} 基本原理就是首次或者第一次执行时,把下一次执行的时间先计算出来放到 DelayQueue 中去,时间一到用 take 就能立即将其取出。 7楼的强.但没有用过.所以,暂时学习一下你的思路,写一些demo.我现在将时间设置成23点,并加时间判断.谢谢各位,结贴了. java问题 一个另我太疑惑的问题???求救~~~ 贪吃蛇的小问题 怎么实现填充颜色的渐变效果?????? 创建一个空的linkdeList通过ListIterator,将若干个Integer插入这个List,怎么实现的? 郁闷阿!高分寻求解决办法!!关于java的签名验证,在线等待!!!!! 想编写一个程序。。。。。。求助。。。 求高手点拨一个“打开网址”的Java功能源代码的“一个功能调用打开两个页面”的原因... 求助~数3退1 循环数组实现运行出错,提示数组越界 哇靠,StringBuffer竟然没有提供清空功能 那位正则高手帮我解释下这个 第一次看TIJ,请教一些杂乱的问题
我们平时所用的JVM无法解决你的这个问题 道理很简单 你觉得timer帮你跑一边 long delayTime = 24*60*60*1000; 的精度有多准。不过有一部分人正奋斗在这个time-critical java中,java有另外一个版本叫做 java real-time system
他是一个还没有实用价值的版本。但是在这个版本中可以做到时间的完全精度化 而且 可以使用像 下周3,12天后,这样的时间计量。有兴趣可以看看 http://java.sun.com/javase/technologies/realtime/index.jsp#jsr-001
不过目前没有太大的实用价值
现在已经有2个问题了.
1.可能会执行任务.
--->应该是:一天内可能会执行多次任务.
因为启动时过了指定的时间,就会立即执行.
我现在想到的办法:只有把指定的晚一点.比如指定到23:50分这个样子. 2.下次执行任务时间会被更改.
--->任务执行间隔,以上次为准.
如
setxxx(Date date) {
if (time == null) {...}
else {timer.cancel();}
timer.schedule(task, date,delayTime);
}
当重启时,setxxx(new Date()),指定启动时 setxxx(sometime);
if (date.getTime() < System.currentTimeMillis()) {
date = new Date(date.getTime() + 24 * 60 * 60 * 1000);
}Timer timer = new Timer();
if (configSerial()) {
timer.schedule(new MyTimerTask(), date, 24 * 60 * 60 * 1000);
showRunningDialog(timer);
}
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class DelayQueueTest { public static void main(String[] args) throws InterruptedException { SchedulerManager manager = new SchedulerManager();
manager.addJob(new EveryMinuteDelay(new MyJob()));
manager.start(); printCurrentTime();
sleepMinutes(3); // 休息 3 分钟后关掉
manager.stop(); // 停止工作
printCurrentTime();
} private static void sleepMinutes(long minutes) {
try {
TimeUnit.MINUTES.sleep(minutes);
} catch (InterruptedException e) {
e.printStackTrace();
}
} private static void printCurrentTime() {
System.out.printf("Current: %tF %<tT%n", System.currentTimeMillis());
}
}/**
* <p>任务调度管理器</p>
*
* 2010-5-28 下午11:30:20
*/
class SchedulerManager { private ExecutorService executor;
private DelayQueue<JobDelayed> jobs;
private Scheduler scheduler; public SchedulerManager() {
this(1);
} /**
* 根据线程池中线程数量构造调度管理器
* @param threadPool
*/
public SchedulerManager(int threadPool) {
this.jobs = new DelayQueue<JobDelayed>();
// 由于调度管理器需要占用一个线程,因此需要加 1
this.executor = Executors.newFixedThreadPool(threadPool + 1);
this.scheduler = new Scheduler(this);
} /**
* <p>添加需要计划的任务</p>
*
* @param job
*/
public void addJob(JobDelayed jobDelayed) {
jobDelayed.nextTime(); // 计算下一次执行的时间
jobs.put(jobDelayed); // 添加到延迟队列中去
} public void start() {
scheduler.start(); // 启动任务调度器
} public void stop() {
scheduler.stop(); // 停止任务调度器
} private void execute() throws InterruptedException {
submit(take());
} /**
* <p>将任务提交给线程池去执行</p>
*
* @param task
*/
private void submit(Runnable task) {
executor.submit(task);
} /**
* <p>强制停止工作</p>
*/
private void shutdown() {
executor.shutdown();
} /**
* <p>获取到时间的任务,如果该任务下一次还需要执行,将该任务加回队列中去。</p>
*
* @return
* @throws InterruptedException
*/
private JobDelayed take() throws InterruptedException {
JobDelayed jobDelayed = jobs.take();
if(jobDelayed.hasNext()) {
addJob(jobDelayed);
}
return jobDelayed;
} /**
* <p>调度器</p>
* 2010-5-28 下午11:40:58
*/
private static class Scheduler implements Runnable { private SchedulerManager manager;
private boolean running = false; /**
* 使用调度管理器构造
* @param manager
*/
public Scheduler(SchedulerManager manager) {
this.manager = manager;
} /**
* <p>启动该调度器</p>
*/
public void start() {
if(!running) {
manager.submit(this);
this.running = true;
}
} /**
* 执行任务调度工作
*/
@Override
public void run() {
while(running) {
try {
manager.execute();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} /**
* <p>强制停止该调度器</p>
*/
public void stop() {
manager.shutdown();
running = false;
}
}
}/**
* <p>需要进行任务调度的工作内容</p>
*/
interface Job {
public void execute();
}/**
* <p>测试工作,输出当前时间</p>
*/
class MyJob implements Job {
public void execute() {
System.out.printf("JOB OUTPUT: %tF %<tT%n", System.currentTimeMillis());
}
}/**
* <p>需要进行调度工作的任务</p>
*/
interface JobDelayed extends Delayed, Runnable { /**
* <p>计算下一次执行的时间</p>
*/
public void nextTime(); /**
* <p>下一次是否需要执行</p>
*/
public boolean hasNext();
}/**
* <p>需要进行每分钟调度工作的任务</p>
*/
class EveryMinuteDelay implements JobDelayed { private long nextTime;
private Job job; public EveryMinuteDelay(Job job) {
this.job = job;
} public void nextTime() {
Calendar c = Calendar.getInstance();
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
c.add(Calendar.MINUTE, 1);
this.nextTime = c.getTimeInMillis(); // 这个任务的 nextTime 为下一分钟
} public boolean hasNext() {
return true; // 永远执行下去
} @Override
public long getDelay(TimeUnit unit) {
return nextTime - System.currentTimeMillis(); // 是否超时
} @Override
public int compareTo(Delayed o) {
return (int)(o.getDelay(TimeUnit.MILLISECONDS) - getDelay(TimeUnit.MILLISECONDS));
} @Override
public void run() {
job.execute(); // 执行任务
} public String toString() {
return String.format("next: %tF %<tT", nextTime);
}
}