如何在 Java 中设置定时器?

Posted

技术标签:

【中文标题】如何在 Java 中设置定时器?【英文标题】:How to set a Timer in Java? 【发布时间】:2011-05-01 23:28:30 【问题描述】:

如何设置一个定时器,比如 2 分钟,尝试连接到数据库,如果连接有任何问题,则抛出异常?

【问题讨论】:

能否让 OP 澄清他们是否希望简单地尝试该操作至少 2 分钟,或者是否必须在两分钟后立即抛出异常,即使当前正在尝试连接 【参考方案1】:

所以答案的第一部分是如何做主题要求的,因为这是我最初解释它的方式,并且一些人似乎觉得有帮助。这个问题已经得到澄清,我已经扩展了答案来解决这个问题。

设置计时器

首先你需要创建一个定时器(我在这里使用java.util 版本):

import java.util.Timer;

..

Timer timer = new Timer();

一旦你想运行任务:

timer.schedule(new TimerTask() 
  @Override
  public void run() 
    // Your database code here
  
, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);

让任务在你将做的持续时间后重复:

timer.scheduleAtFixedRate(new TimerTask() 
  @Override
  public void run() 
    // Your database code here
  
, 2*60*1000, 2*60*1000);

// Since Java-8
timer.scheduleAtFixedRate(() -> /* your database code here */, 2*60*1000, 2*60*1000);

使任务超时

要具体执行澄清问题所要求的内容,即尝试在给定时间段内执行任务,您可以执行以下操作:

ExecutorService service = Executors.newSingleThreadExecutor();

try 
    Runnable r = new Runnable() 
        @Override
        public void run() 
            // Database task
        
    ;

    Future<?> f = service.submit(r);

    f.get(2, TimeUnit.MINUTES);     // attempt the task for two minutes

catch (final InterruptedException e) 
    // The thread was interrupted during sleep, wait or join

catch (final TimeoutException e) 
    // Took too long!

catch (final ExecutionException e) 
    // An exception from within the Runnable task

finally 
    service.shutdown();

如果任务在 2 分钟内完成,这将正常执行,但会出现异常。如果运行时间超过这个时间,就会抛出 TimeoutException。

一个问题是,尽管两分钟后您会收到 TimeoutException,但任务实际上会继续运行,尽管可能数据库或网络连接最终会超时并在线程。但请注意,在这种情况发生之前它可能会消耗资源。

【讨论】:

哦,我猜你的问题搞错了,我每次都要反复尝试连接数据库直到 2 分钟 读者注意:这个答案是明显错误的。它设置一个计时器等待 2 分钟,然后在 2 分钟延迟后运行数据库查询,然后每 2 分钟一次又一次地运行它。它不做的是立即运行数据库查询,然后在 2 分钟后失败,这就是我认为问题所要求的(如评论中所述)。 @AgilePro 确实如此。我没有回答这个问题,因为它最终被陈述了,我现在已经更新它来解决这个问题。 @ErnestasGruodis 核心 API 将构造函数列为公共:docs.oracle.com/javase/7/docs/api/java/util/Timer.html#Timer() 您的类路径中可能有不同的 Timer 类 - 尝试将 java.util.Timer 作为类。 如何将 timer.schedule() 与 lambda 表达式一起使用(从 java 8 开始)? TimerTask(first parameter) 甚至不是功能接口。 TimerTask 只是一个抽象类。【参考方案2】:

好的,我想我现在明白你的问题了。您可以使用 Future 尝试做某事,然后如果什么都没发生,则在一段时间后超时。

例如:

FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() 
  @Override
  public Void call() throws Exception 
    // Do DB stuff
    return null;
  
);

Executor executor = Executors.newSingleThreadScheduledExecutor();
executor.execute(task);

try 
  task.get(5, TimeUnit.SECONDS);

catch(Exception ex) 
  // Handle your exception

【讨论】:

抛出异常但程序没有被终止。请帮助我完成这个。 您可以使用 ExecutorService 类代替 Executor。它有shutdown()方法来停止执行器。 Executors 将吞下您在 Callable/Runnable 中未专门处理的抛出异常。如果您的 Runnable/Callable 本身没有捕获和处理异常并且它是提供给您而不是您拥有它,那么您需要继承 ScheduledExecutorService 并覆盖 afterExecute(确保调用 super.afterExecute())。 afterExecute 的第二个参数将是 Runnable/Callable 中的 throwable【参考方案3】:

使用这个

long startTime = System.currentTimeMillis();
long elapsedTime = 0L.

while (elapsedTime < 2*60*1000) 
    //perform db poll/check
    elapsedTime = (new Date()).getTime() - startTime;


//Throw your exception

【讨论】:

hmm...这在技术上是可行的,但它不包括边缘情况,在这种情况下,当您执行数据库轮询时,时间用完,这可能是 OP 需要的 这是唯一正确的答案。它将在单个线程上运行,并将计算结束时间而不会漂移。在这种情况下,使用 TimerTask 完全是错误的做法。我很惊讶 *** 上有多少例子表明了同样的错误。 @thecoshman - 定时器实现不会中断正在进行的数据库操作,这也不会。无论如何,您只能控制启动 DB 操作的时间。有一个常见的误解是你需要一个“计时器”来计时,但你不需要。您只需要做某事,并使用当前时间确保您不会做太久。 假设您必须在两分钟后返回连接或抛出,这将不起作用。如果在尝试连接两分钟后仍然无法连接,则会出现这种情况。在连接检查需要两周时间的情况下,抛出异常需要很长时间。 这实际上是一种非常糟糕的编码风格,因为 while 循环不断运行并检查内容……对 CPU 不利,对电池寿命不利。【参考方案4】:
    new java.util.Timer().schedule(new TimerTask()
        @Override
        public void run() 
            System.out.println("Executed...");
           //your code here 
           //1000*5=5000 mlsec. i.e. 5 seconds. u can change accordngly 
        
    ,1000*5,1000*5); 

【讨论】:

只要复制代码上面的代码就可以了。我给了两次“时间”,第一次是第一次执行这段代码,第二次是间隔时间。 Timer 的文档建议改用 Executor 框架。 docs.oracle.com/javase/10/docs/api/java/util/Timer.html【参考方案5】:

[android] 如果有人希望在 Android 上使用 java 实现 计时器

你需要像这样使用UI线程来执行操作。

Timer timer = new Timer();
timer.schedule(new TimerTask() 
           @Override
            public void run() 
                ActivityName.this.runOnUiThread(new Runnable()
                    @Override
                      public void run() 
                       // do something
                              
                );
            
        , 2000));

【讨论】:

以上是关于如何在 Java 中设置定时器?的主要内容,如果未能解决你的问题,请参考以下文章

如何在javascript中设置定时间隔?

如何在Windows应用程序中设置用户空闲或不活动时的定时器。

如何在android中设置计时器?

如何在symfony 2.x中设置控制台命令的定时器?

如何在 Ogre 3D 中设置计时器?

求大神!!如何在MFC中设置一个计时器?