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

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

【问题讨论】:

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

标签: java timer


【解决方案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 完全是错误的做法。我很惊讶 StackOverflow 上有多少例子表明了同样的错误。
  • @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); 

【讨论】:

【解决方案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));

【讨论】:

    猜你喜欢
    • 2013-10-25
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 2014-02-13
    • 1970-01-01
    • 2016-10-30
    相关资源
    最近更新 更多