在Java中如何调用线程在特定时间运行?

12

我想让线程在特定的准确时间执行(例如在:2012-07-11 13:12:24和2012-07-11 15:23:45)。

我查看了ScheduledExecutorService,但它只支持从第一次运行后经过特定时间后执行,并且我没有任何固定的时间间隔,而是有来自数据库要执行任务的时间。

在以前关于不同问题的一个问题here, TimerTask是解决方案,但显然我不能把线程作为TimerTask,因为RunnableTimerTask都有需要实现的run方法。这里的问题是如果我让线程扩展TimerTask并具有一个run()实现,那会起作用吗? 如果不是,那么如何做到我所尝试的事情?


1
重构你的解决方案,不要创建自己的线程。改为继承TimerTask - Marko Topolnik
@MarkoTopolnik,那会解决冲突...但实际上我需要线程,因为我将有许多任务(有四种类型的任务),我希望每个单独的任务在一个线程中执行。 - Sami
1
然后创建一个薄的TimerTask包装器,其中包含您的线程作为实例变量,并将在预定时间启动您的线程。您甚至可以使用匿名的TimerTask子类,通过闭合本地变量来查看该线程。现在我看到@AkhilDev正是在下面提出这个建议 :) - Marko Topolnik
3个回答

17

使用 TimerTask 。

创建一个 TimerTask 对象,并将其作为您的线程字段变量。 从计时器任务 Run 方法中调用线程启动。

public class SampleTask extends TimerTask {
  Thread myThreadObj;
  SampleTask (Thread t){
   this.myThreadObj=t;
  }
  public void run() {
   myThreadObj.start();
  }
}

像这样进行配置。

Timer timer  new Timer();
Thread myThread= // Your thread
Calendar date = Calendar.getInstance();
date.set(
  Calendar.DAY_OF_WEEK,
  Calendar.SUNDAY
);
date.set(Calendar.HOUR, 0);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
// Schedule to run every Sunday in midnight
timer.schedule(
  new SampleTask (myThread),
  date.getTime(),
  1000 * 60 * 60 * 24 * 7
);

1
这种情况可能是由于我从数据库中获取任务的方式导致的。我有一个线程,每分钟使用executerService运行一次,该线程查找下一分钟内到期的任何任务并提取它们。如果任务在检查后仅在一秒钟内到期,则将考虑将其用于下一个fetcher线程的执行。但是,由于它将在获取线程时间后的一秒钟内到期,因此可能会被延迟执行或甚至安排晚。如何改进这种情况? - Sami
创建两个任务实例,分别配置不同的时间,并调度这两个实例。 - Akhi
但这将执行两次任务..并且任务将结果存储在数据库中。因此,执行两次会创建问题..我实际上正在尝试避免执行相同任务两次。 - Sami
抱歉有点混淆了,这是第一个问题带来的另一个问题。不管怎样,我想我让它变得复杂了,时序问题可能性很小,也不会对结果产生影响,所以现在不考虑它了。我尝试了你的解决方案,它对我起作用了。谢谢 :) - Sami
1
如果您从代码的最后一行中删除数字7,即将其更改为:timer.schedule( new SampleTask (myThread), date.getTime(), 1000 * 60 * 60 * 24 ); 那么这将使任务每天在午夜重复执行,从星期日开始。显然,您可以将星期日更改为任何其他时间。 - Sami
显示剩余3条评论

4

我认为你最好使用一些类库,比如Quartz Scheduler。这基本上是Java的cron实现。


2

你有没有看过来自java.util.concurrent包的CountDownLatch?它提供了一个倒计时,然后触发线程运行。我自己从未使用过它,但见过它被使用几次。


1
在请求的时间调用 Thread.start 会更简单。 - Marko Topolnik
一个 for 循环可能会有帮助。 (顺便说一下,我不会给你点踩)。 - Marko Topolnik
2
@MarkoTopolnik:好的,别担心,我猜...显然有人给这个答案投了反对票,如果那个人能友善地解释一下为什么就好了 :) - posdef
1
我完全同意。事实上,在我的观点中,对待其他SO用户唯一公平的行为是:1. 留下评论;2. 给回答者至少5分钟的回应时间;3. 如果其他方法都无效,才进行downvote。 - Marko Topolnik
CountDownLatch是一个完美的解决方案,特别是在尝试对声称是线程安全的外部API进行测试时。在for循环中生成线程,让它们等待startSignal,然后全部调用API。使用doneSignal来知道何时可以安全地验证API是否进行了更改,以便于测试代码。 - GMLewisII
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接