Java基础任务调度推荐使用ScheduledExecutorService而非Timer,因其支持线程池、异常隔离与灵活生命周期管理;需注意线程安全、异常捕获及资源释放。

Java中实现基础任务调度,核心在于利用线程与时间控制机制,在指定时刻或按固定周期执行任务。不依赖Spring或Quartz等框架,纯SDK方案更利于理解底层逻辑和应对轻量级场景。
使用Timer + TimerTask实现简单定时任务
Timer是Java早期提供的轻量级调度工具,适合单任务、低并发、精度要求不高的场景。它基于单后台线程驱动所有任务,若某任务执行时间过长,会影响后续任务的触发时间。
- 创建继承TimerTask的类,重写run()方法定义具体逻辑
- 实例化Timer,调用schedule()或scheduleAtFixedRate()启动任务
- schedule(task, delay):延迟delay毫秒后执行一次
- schedule(task, firstTime, period):首次在firstTime执行,之后每period毫秒执行一次(以实际完成时间为起点计算下一次)
- scheduleAtFixedRate(task, firstTime, period):严格按周期推进,即使某次执行延迟,也会尝试“追赶”(可能连续触发)
使用ScheduledExecutorService替代Timer
推荐优先使用ScheduledThreadPoolExecutor(通过Executors.newScheduledThreadPool()获取),它是Timer的现代升级版,基于线程池,支持多任务并行、异常隔离、更灵活的生命周期管理。
- 调用schedule(Runnable, delay, TimeUnit)执行单次延迟任务
- 调用scheduleAtFixedRate(Runnable, initialDelay, period, TimeUnit)实现固定速率周期执行
- 调用scheduleWithFixedDelay(Runnable, initialDelay, delay, TimeUnit)实现固定延迟执行(以上一次任务结束为下一次开始计时)
- 务必在应用退出前调用shutdown()或shutdownNow()释放资源
注意线程安全与异常处理
调度任务运行在线程池或Timer线程中,若任务抛出未捕获异常,该线程会终止,后续任务不再执行——这是常见故障点。
立即学习“Java免费学习笔记(深入)”;
- 在run()或Runnable实现中主动包裹try-catch,记录日志并继续流程
- 避免在任务中直接操作非线程安全对象(如ArrayList、SimpleDateFormat),改用ConcurrentHashMap、DateTimeFormatter等线程安全替代品
- 若需共享状态,使用AtomicInteger、ReentrantLock或synchronized保障一致性
一个可运行的最小示例
以下代码每2秒打印当前时间,持续10秒后自动停止:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
AtomicInteger count = new AtomicInteger(0);
ScheduledFuture> future = scheduler.scheduleAtFixedRate(() -> {
System.out.println("执行中: " + new Date() + ", 次数: " + count.incrementAndGet());
}, 0, 2, TimeUnit.SECONDS);
// 10秒后取消任务
scheduler.schedule(() -> {
future.cancel(true);
scheduler.shutdown();
}, 10, TimeUnit.SECONDS);










