system.currenttimemillis() 仅返回当前毫秒值,需结合循环或scheduledexecutorservice实现秒级定时任务;推荐使用scheduledexecutorservice,支持线程安全、多任务及取消,手动对齐整秒需计算初始延迟。

System.currentTimeMillis() 本身不是定时任务工具,它只是返回当前时间的毫秒值。要实现秒级定时任务,需要用它来判断时间间隔,再配合循环或调度机制。
用 while 循环 + currentTimeMillis 实现简单秒级轮询
适合轻量、短时、不需高精度的场景(比如每秒检查一次状态)。核心是记录上一次执行时间,每次循环计算是否满 1 秒。
- 用一个 long 变量保存上次执行的时间戳(初始为 System.currentTimeMillis())
- 循环中获取当前时间戳,减去上次时间,若 ≥ 1000 毫秒,则执行任务,并更新“上次时间”
- 注意加 Thread.sleep(10~100) 避免空转耗 CPU,但不要 sleep(1000),否则可能跳过整秒点
示例:
while (running) {
long now = System.currentTimeMillis();
if (now - lastRun >= 1000) {
// 执行任务
lastRun = now;
}
Thread.sleep(50); // 小休眠降低开销
}
用 ScheduledExecutorService 实现更可靠的秒级调度
这是推荐方式:线程安全、支持多任务、可取消、底层基于系统时钟和队列,比手动轮询更健壮。
- 创建单线程调度器:ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
- 调用 scheduleAtFixedRate(Runnable, initialDelay, period, TimeUnit.SECONDS),period 设为 1 即每秒执行
- 注意:initialDelay 是首次延迟,不是“从现在开始算整秒”,如想在下一个整秒触发,需手动对齐(见下一条)
对齐到整秒时刻执行(可选增强)
如果要求严格在 00:00:00、00:00:01 这样的整秒点运行(比如日志打点、监控上报),需计算首次延迟:
- 获取当前时间毫秒值:long now = System.currentTimeMillis()
- 算出距离下一个整秒还剩多少毫秒:long delay = 1000 - (now % 1000)
- 若 delay == 1000(恰好在整秒上),delay 设为 0;否则用 delay 作为 initialDelay
- 再用 scheduleAtFixedRate(..., delay, 1, TimeUnit.SECONDS)
注意事项和常见误区
- System.currentTimeMillis() 受系统时钟调整影响(如 NTP 校时),可能导致重复或漏执行;高精度场景建议用 System.nanoTime() 做间隔测量,但不能用于绝对时间
- 不要用 Timer 类——它只有一个后台线程,任务抛异常会导致后续全部失效;ScheduledExecutorService 更可靠
- 避免在定时任务里做阻塞操作(如 IO、锁等待),否则会拖慢后续执行;必要时用异步或超时控制
- 记得 shutdown() 调度器,防止线程泄漏
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











