40

我想在 java.utils.Timer 中有一个可重置时间的 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 并涉及停止原始计时器并创建一个新计时器。IE:

timer.stop();
timer = new Timer(8000, ActionListener);
timer.start();

有没有更简单的方法??

4

8 回答 8

50

根据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.

于 2008-08-28T11:52:00.717 回答
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似乎也没有内置支持重新安排现有任务,但类似的方法也应该在那里工作。

于 2008-08-28T12:25:23.693 回答
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);        
        }
      }


}
于 2012-11-27T11:40:20.403 回答
1

您是否需要安排重复性任务?在这种情况下,我建议您考虑使用Quartz

于 2008-08-28T10:54:30.247 回答
1

我不认为Timer/TimerTask使用java.util.concurrent.ScheduledThreadPoolExecutor.

于 2008-08-28T11:47:18.623 回答
1

这就是我正在尝试的。我有一个类使用 TimerTask 每 60 秒轮询一次数据库。

在我的主类中,我保留了 Timer 的实例,以及 TimerTask 的本地子类的实例。主类有一个方法来设置轮询间隔(比如从 60 到 30)。在其中,我取消了我的 TimerTask(这是我的子类,我在其中重写了 cancel() 方法来进行一些清理,但这不重要),然后将其设为 null。我重新创建它的一个新实例,并在现有计时器中以新间隔安排新实例。

由于 Timer 本身没有被取消,它使用的线程保持活动状态(其中的任何其他 TimerTasks 也会保持活动状态),并且旧的 TimerTask 被替换为一个新的,恰好是相同的,但是 VIRGIN(因为旧的会被执行或调度,它不再是 VIRGIN,因为调度需要)。

当我想关闭整个计时器时,我取消 TimerTask 并将其清空(与我在更改时间时所做的相同,再次清理我的 TimerTask 子类中的资源),然后我取消并清空 Timer 本身。

于 2009-04-16T14:09:11.343 回答
0

这是可重置计时器的示例。尝试更改它以供您使用...

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 秒打印一次当前日期和时间...但是如果您在控制台中提供任何输入,则计时器将被延迟以执行给定的输入任务...

于 2012-12-05T09:53:52.823 回答
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);
  }
}
于 2018-07-20T16:33:21.770 回答