如何使用 Timer 类调用方法,做某事,重置计时器,重复?

Posted

技术标签:

【中文标题】如何使用 Timer 类调用方法,做某事,重置计时器,重复?【英文标题】:How to use Timer class to call a method, do something, reset timer, repeat? 【发布时间】:2012-03-13 21:27:33 【问题描述】:

我是一名 Java 初学者,一直在尝试解决这个问题的各种解决方案,并且让自己陷入了困境。我已经尝试过使用 Threads,然后发现了这个 Timer 类,并且到目前为止一直没有成功。如果您可以发布带有 main 方法的可执行代码,这样我就可以看到它正在工作并从那里开始玩,那就太好了。

    启动程序 致电doSomething() 生成随机数并设置 Timer 的时间。 当定时器响起时,再次拨打doSomething()

可能使用这个:http://docs.oracle.com/javase/6/docs/api/java/util/Timer.html

【问题讨论】:

不要对定时器执行此操作。使用 java.util.concurrent 中的一些东西。它更容易理解、性能更高、更健壮。下面 SimonC 的示例是一种不错的方法。 【参考方案1】:

设想一个场景,我希望我的代码在我的应用程序中的特定时间执行,或者在当前时间之后的某个时间执行。换句话说,我想在确定的时间安排我的任务。

Java Timer 类 (java.util.Timer) 允许应用程序在单独的后台线程上安排任务。

这里是最简单的example of Java Timer:

import java.util.Timer;
import java.util.TimerTask;
public class JavaTimer 
    public static void main(String[] args) 
        Timer timer = new Timer();
        TimerTask task = new TimerTask() 
            @Override
            public void run() 
                System.out.println("Inside Timer Task" + System.currentTimeMillis());
            
        ;

        System.out.println("Current time" + System.currentTimeMillis());
        timer.schedule(task, 10000,1000);
        System.out.println("Current time" + System.currentTimeMillis());
    


Output:
Current time1455469505220
Current time1455469505221
Inside Timer Task1455469515222
Inside Timer Task1455469516222
Inside Timer Task1455469517222
Inside Timer Task1455469518222
Inside Timer Task1455469519222
Inside Timer Task1455469520222
Inside Timer Task1455469521222
Inside Timer Task1455469522222
Inside Timer Task1455469523222
Inside Timer Task1455469524222
Inside Timer Task1455469525222
Inside Timer Task1455469526222
Inside Timer Task1455469527222
Inside Timer Task1455469528223
Inside Timer Task1455469529223 and it goes on

分析: 对 timer.schedule(task, 10000,1000) 的调用将安排在此调用 10 秒后第一次(在另一个线程上)执行的任务。之后,它会在延迟 10 秒后再次调用。这里需要提一下,如果任务在 10 秒后无法启动,下一个任务调用将不会得到 pre-pond。所以这里两个连续任务之间的延迟时间是固定的。

来源:Java Timer Example

【讨论】:

【参考方案2】:

下面的代码将在 18:20 运行,它会每隔 5 秒重复一次。

public static void main(String[] args) 
    Timer timer = new Timer();
    TimerTask tt = new TimerTask() 
        public void run() 
            Calendar cal = Calendar.getInstance();

            int hour = cal.get(Calendar.HOUR_OF_DAY);
            int min = cal.get(Calendar.MINUTE);
            if (hour == 18 && min == 20) 
                doSomething();
            
        
    ;
    timer.schedule(tt, 1000, 5000);

【讨论】:

【参考方案3】:

如果你想简单地使用 Timer,我会这样做:

public class TestClass 
    public long myLong = 1234;

    public static void main(String[] args) 
        final TestClass test = new TestClass();

        Timer timer = new Timer();
        timer.schedule(new TimerTask() 

            @Override
            public void run() 
                test.doStuff();
            
        , 0, test.myLong);
    

    public void doStuff()
        //do stuff here
    

对不起,糟糕的识别。

另外,如果您需要安排代码的执行,请查看Guava Services,因为它确实可以让您的代码更清晰,并抽象出相当多的创建线程、调度等样板。

顺便说一句,我没有费心生成随机数等,但我想你可以弄清楚如何包含那部分。我希望这足以让您走上正轨。

为了记录,如果你使用 Guava,它看起来像这样:

class CrawlingService extends AbstractScheduledService 

    @Override
    protected void runOneIteration() throws Exception 
        //run this alot
    

    @Override
    protected void startUp() throws Exception 
        //anything you need to step up
    

    @Override
    protected void shutDown() throws Exception 
        //anything you need to tear down
    


    @Override
    protected Scheduler scheduler() 
        return new CustomScheduler() 
            @Override
            protected Schedule getNextSchedule() throws Exception 
                long a = 1000; //number you can randomize to your heart's content
                return new Schedule(a, TimeUnit.MILLISECONDS);
            
        ;
    

您只需创建一个名为 new CrawlingService.start(); 的 main就是这样。

【讨论】:

【参考方案4】:

您是否特别想要Timer?如果不是,您最好使用ScheduledExecutorService 并致电scheduleAtFixedRatescheduleWithFixedDelay;引用Javadocs:

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

更新

这是一些使用ScheduledExecutorService 的工作代码:

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test 
    public static void main(String[] args) 
        final ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
        ses.scheduleWithFixedDelay(new Runnable() 
            @Override
            public void run() 
                System.out.println(new Date());
            
        , 0, 1, TimeUnit.SECONDS);
    

输出如下:

Thu Feb 23 21:20:02 HKT 2012
Thu Feb 23 21:20:03 HKT 2012
Thu Feb 23 21:20:04 HKT 2012
Thu Feb 23 21:20:05 HKT 2012
Thu Feb 23 21:20:06 HKT 2012
Thu Feb 23 21:20:07 HKT 2012

【讨论】:

【参考方案5】:

如果您不想使用计时器类并且可以使用 Quartz,请执行它。我的主要课程是

import com.google.common.util.concurrent.AbstractScheduledService;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.TriggerBuilder.newTrigger;

import java.util.concurrent.CountDownLatch;

public class Test 


    public static void main(String[] args) throws Exception


        CountDownLatch latch = new CountDownLatch(1);


        //do schdeuling thing
        JobDetail job = JobBuilder.newJob(SimpleJob.class).withIdentity(
                "CronQuartzJob", "Group").build();

        // Create a Trigger that fires every 5 minutes.
        Trigger trigger = newTrigger()
                .withIdentity("TriggerName", "Group")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/1 * * * * ?"))
                .build();

        // Setup the Job and Trigger with Scheduler & schedule jobs
        final Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        scheduler.start();
        scheduler.scheduleJob(job, trigger);

        //
        latch.await();

        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() 
            @Override
            public void run() 
                try 
                    scheduler.shutdown();
                    latch.countDown();
                catch (Exception e)
                    e.printStackTrace();
                
            
        ));

    







工作类别是

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class SimpleJob implements Job 


    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException 
        System.out.println("executing task!");
    



我会为此创建一个可执行 jar 并使用 java -jar .. &Ctrl+C 启动它可以停止该进程,如果你想要它在后台 disownit

【讨论】:

以上是关于如何使用 Timer 类调用方法,做某事,重置计时器,重复?的主要内容,如果未能解决你的问题,请参考以下文章

C# 如何用计时器Timer控件实现停留几秒再做切换窗体的操作

使用 XCTest 在 Xcode 中测试计时器

Timer类

unity3d 倒计时器 出现问题

外部类中的 NSTimer

Jquery Countdown Timer 在页面刷新时没有重置?