我希望在java中有一个带有可重置时间的java.utils.Timer。我需要在X秒内设置一次性事件。如果在创建计时器和X秒之间没有任何反应,则事件正常发生。
但是,如果在X秒过去之前,我决定事件应该在Y秒之后发生,那么我希望能够告诉计时器重置其时间,以便事件在Y秒内发生。 例如。计时器应该能够执行以下操作:
Timer timer = new Timer();
timer.schedule(timerTask, 5000); //Timer starts in 5000 ms (X)
//At some point between 0 and 5000 ms...
setNewTime(timer, 8000); //timerTask will fire in 8000ms from NOW (Y).
我没有看到使用utils计时器的方法,就像你调用cancel()一样,你无法再次安排它。
我接近复制此行为的唯一方法是使用javax.swing.Timer并涉及停止原始计时器,并创建一个新计时器。即:
timer.stop();
timer = new Timer(8000, ActionListener);
timer.start();
有更简单的方法吗?
答案 0 :(得分:49)
根据Timer
文档,在Java 1.5及更高版本中,您应该更喜欢ScheduledThreadPoolExecutor
。 (您可能希望使用Executors
.newSingleThreadScheduledExecutor()
创建此执行程序以方便使用;它会创建类似于Timer
的内容。)
很酷的是,当您安排任务时(通过调用schedule()
),它会返回一个ScheduledFuture
对象。您可以使用它来取消计划任务。然后,您可以自由地提交具有不同触发时间的新任务。
ETA:链接到的Timer
文档没有说明ScheduledThreadPoolExecutor
,但OpenJDK版本有这样的说法:
Java 5.0引入了
java.util.concurrent
包和 其中一个并发实用程序是ScheduledThreadPoolExecutor
这是一个重复的线程池 以给定的速率或延迟执行任务。它实际上更多Timer
/TimerTask
的多功能替代品 组合,因为它允许多个服务线程,接受各种 时间单位,并不需要子类TimerTask
(只是 实施Runnable
)。配置ScheduledThreadPoolExecutor
使用一个线程使其等效于Timer
。
答案 1 :(得分:17)
如果您的Timer
只有一个任务要执行,那么我建议继承它:
import java.util.Timer;
import java.util.TimerTask;
public class ReschedulableTimer extends Timer
{
private Runnable task;
private TimerTask timerTask;
public void schedule(Runnable runnable, long delay)
{
task = runnable;
timerTask = new TimerTask()
{
@Override
public void run()
{
task.run();
}
};
this.schedule(timerTask, delay);
}
public void reschedule(long delay)
{
timerTask.cancel();
timerTask = new TimerTask()
{
@Override
public void run()
{
task.run();
}
};
this.schedule(timerTask, delay);
}
}
您需要处理代码以添加错误使用的检查,但它应该实现您想要的。 ScheduledThreadPoolExecutor
似乎也不支持重新安排现有任务,但类似的方法也应该在那里工作。
答案 2 :(得分:3)
整个代码片段都是这样的......我希望它能完全帮助
{
Runnable r = new ScheduleTask();
ReschedulableTimer rescheduleTimer = new ReschedulableTimer();
rescheduleTimer.schedule(r, 10*1000);
public class ScheduleTask implements Runnable {
public void run() {
//Do schecule task
}
}
class ReschedulableTimer extends Timer {
private Runnable task;
private TimerTask timerTask;
public void schedule(Runnable runnable, long delay) {
task = runnable;
timerTask = new TimerTask() {
public void run() {
task.run();
}
};
timer.schedule(timerTask, delay);
}
public void reschedule(long delay) {
System.out.println("rescheduling after seconds "+delay);
timerTask.cancel();
timerTask = new TimerTask() {
public void run() {
task.run();
}
};
timer.schedule(timerTask, delay);
}
}
}
答案 3 :(得分:1)
您是否需要安排定期任务?在这种情况下,我建议您考虑使用Quartz。
答案 4 :(得分:1)
我认为不可能使用Timer/TimerTask
,但根据您想要实现的目标,您可能会对使用java.util.concurrent.ScheduledThreadPoolExecutor
感到满意。
答案 5 :(得分:1)
这就是我正在尝试的。我有一个类,它使用TimerTask每60秒轮询一次数据库。
在我的主类中,我保留了Timer的实例,以及我的TimerTask的本地子类的实例。主类有一个设置轮询间隔的方法(比如从60到30)。在它,我取消我的TimerTask(这是我的子类,我覆盖了cancel()方法进行一些清理,但这应该没关系)然后使其为null。我重新创建它的一个新实例,并在现有Timer中以新的间隔安排新实例。
由于Timer本身没有被取消,它使用的线程保持活动状态(其中的任何其他TimerTasks也是如此),并且旧的TimerTask被替换为新的,恰好相同,但是VIRGIN (因为旧版本将被执行或安排,因此不再是VIRGIN,如调度所需)。
当我想关闭整个计时器时,我取消并取消TimerTask(就像我更改时间时一样,用于清理我的TimerTask子类中的资源),然后我取消并清空Timer本身
答案 6 :(得分:0)
以下是Resetable Timer的示例。试着改变它以获得你的尊重......
package com.tps.ProjectTasks.TimeThread;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* Simple demo that uses java.util.Timer to schedule a task to execute
* every 5 seconds and have a delay if you give any input in console.
*/
public class DateThreadSheduler extends Thread {
Timer timer;
BufferedReader br ;
String data = null;
Date dNow ;
SimpleDateFormat ft;
public DateThreadSheduler() {
timer = new Timer();
timer.schedule(new RemindTask(), 0, 5*1000);
br = new BufferedReader(new InputStreamReader(System.in));
start();
}
public void run(){
while(true){
try {
data =br.readLine();
if(data != null && !data.trim().equals("") ){
timer.cancel();
timer = new Timer();
dNow = new Date( );
ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("Modified Current Date ------> " + ft.format(dNow));
timer.schedule(new RemindTask(), 5*1000 , 5*1000);
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
System.out.format("Printint the time and date was started...\n");
new DateThreadSheduler();
}
}
class RemindTask extends TimerTask {
Date dNow ;
SimpleDateFormat ft;
public void run() {
dNow = new Date();
ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("Current Date: " + ft.format(dNow));
}
}
此示例每5秒打印一次当前日期和时间...但是如果您在控制台中提供任何输入,则计时器将被延迟以执行给定的输入任务......
答案 7 :(得分:0)
出于类似的目的,我制作了自己的计时器类;随时使用它:
public class ReschedulableTimer extends Timer {
private Runnable mTask;
private TimerTask mTimerTask;
public ReschedulableTimer(Runnable runnable) {
this.mTask = runnable;
}
public void schedule(long delay) {
if (mTimerTask != null)
mTimerTask.cancel();
mTimerTask = new TimerTask() {
@Override
public void run() {
mTask.run();
}
};
this.schedule(mTimerTask, delay);
}
}