任务调度之Java Timer
1、前言
在Java中如果需要定时执行某些任务,可以使用java.util包提供Timer和TimerTask,在后台线程中调度任务。 简单来说,TimerTask是要执行的任务,Timer是调度程序。
2、运行一个定时任务
使用Timer的来运行一个定时任务
1 2 3 4 5 6 7 8 9 10 11 12 | @Test public void testTimer_SchedulingTaskOnce() throws Exception { TimerTask task = new TimerTask() { public void run() { System.out.println( "Task performed on: " + new Date() + "n" + "Thread's name: " + Thread.currentThread().getName()); } }; Timer timer = new Timer( "Timer" ); long delay = 1000L; timer.schedule(task, delay); Thread.sleep(delay * 2 ); } |
3. 重复执行定时任务
如何定义一个以预定义的时间间隔运行的任务。使用scheduleAtFixedRate(repeatedTask,delay,period)方法。它在指定的延迟(delay)之后,间隔指定的时间段(period),重复执行的任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Test public void testTimer_SchedulingRepeatedTask() throws InterruptedException { TimerTask repeatedTask = new TimerTask() { public void run() { System.out.println( "Task performed on " + new Date()); } }; Timer timer = new Timer( "Timer" ); long delay = 1000L; long period = 1000L; timer.scheduleAtFixedRate(repeatedTask, delay, period); Thread.sleep(delay * 10 ); } |
如果执行因为一些原因(例如垃圾收集或其他后台活动)而延迟,则会快速连续执行两次或更多次执行以“赶上”正常的执行次数。
3.1 定义每天执行的任务
下面,定义一个每天都执行的任务:
1 2 3 4 5 6 7 8 9 10 11 12 | @Test public void testTimer_SchedulingDailyTask() { TimerTask repeatedTask = new TimerTask() { public void run() { System.out.println( "Task performed on " + new Date()); } }; Timer timer = new Timer( "Timer" ); long delay = 1000L; long period = 1000L * 60L * 60L * 24L; timer.scheduleAtFixedRate(repeatedTask, delay, period); } |
4.取消定时器和定时任务
可以通过以下几种方式取消任务的执行:
4.1 取消运行中的TimerTask
TimerTask本身的实现类里,通过在run()方法的中调用TimerTask.cancel()方法:
1 2 3 4 5 6 7 8 9 10 11 12 | @Test public void testTimer_CancelingTimerTask() throws InterruptedException { TimerTask task = new TimerTask() { public void run() { System.out.println( "Task performed on " + new Date()); cancel(); } }; Timer timer = new Timer( "Timer" ); timer.scheduleAtFixedRate(task, 1000L, 1000L); Thread.sleep(1000L * 10 ); } |
执行上面的代码,会发现TimerTask只被执行了一次。
4.2 取消定时器
通过在Timer对象上调用Timer.cancel()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Test public void testTimer_CancelingTimer() throws InterruptedException { TimerTask task = new TimerTask() { public void run() { System.out.println( "Task performed on " + new Date()); } }; Timer timer = new Timer( "Timer" ); timer.scheduleAtFixedRate(task, 1000L, 1000L); Thread.sleep(1000L * 1 ); timer.cancel(); Thread.sleep(1000L * 9 ); } |
执行上面的代码,会发现TimerTask也只被执行了一次。
4.3 在运行中停止TimerTask的Thread
还可以在任务的run方法中停止线程,从而取消整个任务: 注意运行实现中的TODO指令 - 为了运行这个简单的例子,我们需要实际停止线程。Thread类的stop方法,这个方法已经被废弃了。
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Test public void testTimer_StoppingThread() throws InterruptedException { TimerTask task = new TimerTask() { public void run() { System.out.println( "Task performed on " + new Date()); // TODO: 假如在这里停止 Thread.currentThread().stop(); } }; Timer timer = new Timer( "Timer" ); timer.scheduleAtFixedRate(task, 1000L, 1000L); Thread.sleep(1000L * 2 ); } |
在实际的自定义线程实现中,一般会支持停止线程。
5.Timer VS ExecutorService
可以利用ExecutorService来执行定时器任务,而不是使用定时器。以下是如何以指定间隔运行重复任务的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Test public void testTimer_SchedulingRepeatedTask_ByScheduledExecutorService() throws InterruptedException { TimerTask repeatedTask = new TimerTask() { public void run() { System.out.println( "Task performed on " + new Date()); } }; ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); long delay = 1000L; long period = 1000L; executor.scheduleAtFixedRate(repeatedTask, delay, period, TimeUnit.MILLISECONDS); Thread.sleep(delay + period * 3 ); executor.shutdown(); } |
那么Timer和ExecutorService之间的主要区别是什么:
- 定时器可以对系统时钟的变化敏感; ScheduledThreadPoolExecutor不是
- Timer只有一个执行线程; ScheduledThreadPoolExecutor可以配置任意数量的线程
- 在TimerTask中抛出的运行时异常会杀死一个线程,从而导致Timer死机:(即计划任务将不再运行。ScheduledThreadExecutor不仅捕获运行时异常,还允许在需要时处理它们(通过重写afterExecute方法ThreadPoolExecutor)。抛出异常的任务将被取消,但其他任务将继续运行。
在 JDK1.5 之后,基本不使用 Timer 进行任务调度了。
6 总结
使用Java内置的简单而灵活的Timer和TimerTask基础结构的许多方法,可以快速实现调度任务。如果需要更复杂和完整的解决方案,在Java的世界里还有Quartz等开源框架。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?