如何安排任务定期运行?


76

我正在尝试一些代码以实现预定任务,并提出了这些代码。

import java.util.*;

class Task extends TimerTask {


    int count = 1;

    // run is a abstract method that defines task performed at scheduled time.
    public void run() {
        System.out.println(count+" : Mahendra Singh");
        count++;
    }
}

class TaskScheduling {

   public static void main(String[] args) {
       Timer timer = new Timer();


       // Schedule to run after every 3 second(3000 millisecond)
       timer.schedule( new Task(), 3000);   
   }
}

我的输出:

1  :  Mahendra Singh

我希望编译器以3 s的周期间隔打印一系列Mahendra Singh,但是尽管等待了大约15分钟,但我只得到一个输出...我该如何解决呢?


Quartz Scheduler帮助Java应用程序调度作业/任务以在指定的日期和时间运行,请检查该示例的完整示例
告诉我

1
这些类已被Executors框架取代。请参阅JavaDoc的第7段Timer
罗勒·布尔克

Answers:


77

采用 timer.scheduleAtFixedRate

public void scheduleAtFixedRate(TimerTask task,
                                long delay,
                                long period)

从指定的延迟后开始,调度指定的任务以重复执行固定速率。随后的执行大约每隔固定的时间间隔执行一次,并间隔指定的时间。
在固定速率执行中,相对于初始执行的计划执行时间来计划每个执行。如果执行由于某种原因(例如垃圾回收或其他后台活动)而延迟,则将快速连续发生两个或多个执行以“追赶”。从长远来看,执行频率将恰好是指定时间段的倒数(假设Object.wait(long)底层的系统时钟是准确的)。

固定速率执行适用于对绝对时间敏感的重复活动,例如每小时每小时发出一声提示音,或每天在特定时间运行计划的维护。对于执行固定次数执行的总时间很重要的重复活动,例如倒数计时器,它每秒钟滴答一次十秒钟,这也很适合。最后,固定速率执行适用于安排多个重复计时器任务,这些任务必须彼此保持同步。

参数:

  • 任务-要计划的任务。
  • delay-执行任务之前的延迟(以毫秒为单位)。
  • period-连续执行任务之间的时间(以毫秒为单位)。

抛出:

  • IllegalArgumentException-如果delay为负,或者delay + System.currentTimeMillis()为负。
  • IllegalStateException-如果任务已被调度或取消,计时器被取消或计时器线程终止。

4
scheduleAtFixedRate不能解决仅获得一次输出的问题。
James AN Stauffer

1
@ JamesA.N。Stauffer,他反复需要输出,而不是一次。
st0le 2011年

3
是的,但是重复只是通过添加第三个参数即可实现的-无需更改方法。
James AN Stauffer

2
@ st0le。考虑以下类比。询问者说“天空是蓝色”,问是“不,草是绿色”。-如果他的问题是“固定利率重复率是多少”,您的答案将是理想的。
tony9099 2013年

如果您希望它是某个上限和下限内的随机比率,该怎么办?
Hack-R

80

优势ScheduledExecutorService超过Timer

我希望为您提供一种替代Timer方法-ScheduledThreadPoolExecutor,它是ScheduledExecutorService接口的实现。根据“并发Java”的说法,它比Timer类具有一些优势:

ATimer仅创建一个用于执行计时器任务的线程。如果计时器任务花费的时间太长,则其他计时器的计时精度 TimerTask会受到影响。如果TimerTask安排定期执行一次每10毫秒运行一次,而另一个Timer-Task需要40毫秒才能运行,则长期执行后,重复执行一次任务(取决于是以固定速率还是固定延迟计划的)被连续四次调用正在运行的任务完成,或者完全“丢失”了四个调用。预定线程池通过允许您提供多个线程来执行延迟和定期任务来解决此限制。

Timer的另一个问题是,如果TimerTask 抛出未经检查的异常,它的行为将很差。还有,叫做“线程泄漏”

Timer线程不会捕获该异常,因此,从TimerTask终止抛出的未经检查的异常将终止计时器线程。在这种情况下,Timer也不会使线程复活。而是错误地认为整个计时器已取消。在这种情况下,永远不会运行已安排但尚未执行的TimerTask,并且无法安排新任务。

而另一项建议,如果你需要建立自己的调度服务,您仍然可以通过使用以充分利用图书馆DelayQueue,一个BlockingQueue提供的调度功能的实现ScheduledThreadPoolExecutor。ADelayQueue管理一组延迟的对象。延迟有一个与之相关的延迟时间:DelayQueue仅当延迟已过期时,您才可以使用该元素。对象按DelayQueue顺序返回与其延迟相关的时间。


4
计时器的另一个问题是,更改系统时钟时,计时器会混乱
rajath 2014年

15
public void schedule(TimerTask task,long delay)

计划指定的任务以在指定的延迟后执行。

你要:

public void schedule(TimerTask task, long delay, long period)

从指定的延迟后开始,调度指定的任务以重复执行固定延迟。随后的执行将以指定的时间间隔大致固定的时间间隔进行。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.