可重置的 Java 计时器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32001/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:23:40  来源:igfitidea点击:

Resettable Java Timer

javatimer

提问by Lehane

I'd like to have a java.utils.Timer with a resettable time in java.I need to set a once off event to occur in X seconds. If nothing happens in between the time the timer was created and X seconds, then the event occurs as normal.

我想要一个 java.utils.Timer 在 java.I 中具有可重置的时间。我需要设置一次关闭事件在 X 秒内发生。如果在创建计时器和 X 秒之间没有发生任何事情,则事件将正常发生。

If, however, before X seconds has elapsed, I decide that the event should occur after Y seconds instead, then I want to be able to tell the timer to reset its time so that the event occurs in Y seconds. E.g. the timer should be able to do something like:

但是,如果在 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).

I don't see a way to do this using the utils timer, as if you call cancel() you cannot schedule it again.

我没有看到使用 utils 计时器执行此操作的方法,就像您调用 cancel() 一样,您无法再次安排它。

The only way I've come close to replicating this behavior is by using javax.swing.Timer and involves stopping the origional timer, and creating a new one. i.e.:

我接近复制这种行为的唯一方法是使用 javax.swing.Timer 并涉及停止原始计时器并创建一个新计时器。IE:

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

Is there an easier way??

有更容易的方法吗??

采纳答案by Chris Jester-Young

According to the Timerdocumentation, in Java 1.5 onwards, you should prefer the ScheduledThreadPoolExecutorinstead. (You may like to create this executor using Executors.newSingleThreadScheduledExecutor()for ease of use; it creates something much like a Timer.)

根据Timer文档,从 Java 1.5 开始,您应该更喜欢ScheduledThreadPoolExecutor。(为了便于使用,您可能喜欢创建这个执行程序;它创建的东西很像.)Executors.newSingleThreadScheduledExecutor()Timer

The cool thing is, when you schedule a task (by calling schedule()), it returns a ScheduledFutureobject. You can use this to cancel the scheduled task. You're then free to submit a new task with a different triggering time.

很酷的事情是,当您安排任务时(通过调用schedule()),它会返回一个ScheduledFuture对象。您可以使用它来取消计划任务。然后,您可以自由地提交具有不同触发时间的新任务。

ETA: The Timerdocumentation linked to doesn't say anything about ScheduledThreadPoolExecutor, however the OpenJDKversion had this to say:

ETA:Timer链接到的文档没有说明任何关于ScheduledThreadPoolExecutor,但是OpenJDK版本有这样的说法:

Java 5.0 introduced the java.util.concurrentpackage and one of the concurrency utilities therein is the ScheduledThreadPoolExecutorwhich is a thread pool for repeatedly executing tasks at a given rate or delay. It is effectively a more versatile replacement for the Timer/TimerTaskcombination, as it allows multiple service threads, accepts various time units, and doesn't require subclassing TimerTask(just implement Runnable). Configuring ScheduledThreadPoolExecutorwith one thread makes it equivalent to Timer.

Java 5.0 引入了该java.util.concurrent包,其中的并发实用程序之一 ScheduledThreadPoolExecutor是线程池,用于以给定的速率或延迟重复执行任务。它实际上是Timer/TimerTask组合的更通用的替代品,因为它允许多个服务线程,接受各种时间单位,并且不需要子类化TimerTask(只需实现Runnable)。ScheduledThreadPoolExecutor使用一个线程进行配置 使其等效于 Timer.

回答by Brian Matthews

Do you need to schedule a recurring task? In that case I recommend you consider using Quartz.

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

回答by WMR

I don't think it's possible to do it with Timer/TimerTask, but depending on what exactly you want to achieve you might be happy with using java.util.concurrent.ScheduledThreadPoolExecutor.

我认为不可能Timer/TimerTaskjava.util.concurrent.ScheduledThreadPoolExecutor.

回答by David Sykes

If your Timeris only ever going to have one task to execute then I would suggest subclassing it:

如果您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);
    }
}

You will need to work on the code to add checks for mis-use, but it should achieve what you want. The ScheduledThreadPoolExecutordoes not seem to have built in support for rescheduling existing tasks either, but a similar approach should work there as well.

您将需要处理代码以添加对误用的检查,但它应该可以实现您想要的。在ScheduledThreadPoolExecutor似乎并不具有内置的支持,要么重新安排现有任务,但类似的做法应该工作有作为。

回答by David Sykes

this is what I'm trying out. I have a class that polls a database every 60 seconds using a TimerTask.

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

in my main class, I keep the instance of the Timer, and an instance of my local subclass of TimerTask. the main class has a method to set the polling interval (say going from 60 to 30). in it, i cancel my TimerTask (which is my subclass, where I overwrote the cancel() method to do some cleanup, but that shouldn't matter) and then make it null. i recreate a new instance of it, and schedule the new instance at the new interval in the existing Timer.

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

since the Timer itself isn't canceled, the thread it was using stays active (and so would any other TimerTasks inside it), and the old TimerTask is replaced with a new one, which happens to be the same, but VIRGIN (since the old one would have been executed or scheduled, it is no longer VIRGIN, as required for scheduling).

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

when i want to shutdown the entire timer, i cancel and null the TimerTask (same as i did when changing the timing, again, for cleaning up resources in my subclass of TimerTask), and then i cancel and null the Timer itself.

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

回答by Shaik Khader

The whole Code snippet goes like this .... I hope it will be help full

整个代码片段是这样的......我希望它会有所帮助

{

        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);        
        }
      }


}

回答by Human Being

Here is the example for Resetable Timer . Try to change it for your convinence...

这是可重置计时器的示例。尝试更改它以确保您的信任...

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));
    }
}

This example prints the current date and time for every 5 seconds...But if you give any input in console the timer will be delayed to perform the given input task...

此示例每 5 秒打印一次当前日期和时间……但是如果您在控制台中提供任何输入,则计时器将被延迟以执行给定的输入任务……

回答by luke8800gts

I made an own timer class for a similar purpose; feel free to use it:

为了类似的目的,我制作了一个自己的计时器类;随意使用它:

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);
  }
}