如何在 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 中设置定时器?的主要内容,如果未能解决你的问题,请参考以下文章