一、方法定义
public static long currentTimeMillis()
- 所属类:
java.lang.System
- 返回类型:
long
- 访问修饰符:
public static
- 是否抛出异常:否
该方法是静态方法,无需创建对象即可调用。
二、功能说明
System.currentTimeMillis()
返回当前时间与 UTC 时间 1970年1月1日 00:00:00 之间的毫秒数(即 Unix 时间戳的毫秒形式)。
关键点:
- 基于 协调世界时(UTC),不受本地时区影响(但显示时会受时区影响)。
- 精度为 毫秒级(1/1000 秒)。
- 用于测量时间间隔、生成时间戳、简单计时等。
- 从 Java 1.0 开始支持,是最早的时间 API 之一。
⚠️ 不保证绝对准确,受系统时钟调整(如 NTP 同步)影响。
三、示例代码
1. 获取当前时间戳
long timestamp = System.currentTimeMillis();
System.out.println("当前时间戳(毫秒):" + timestamp);
// 示例输出:1722958765123
2. 计算代码执行时间
long start = System.currentTimeMillis();
// 模拟耗时操作
for (int i = 0; i < 1000000; i++) {
Math.sqrt(i);
}
long end = System.currentTimeMillis();
System.out.println("执行耗时:" + (end - start) + " 毫秒");
3. 转换为可读时间(配合 Date
或 SimpleDateFormat
)
import java.text.SimpleDateFormat;
import java.util.Date;
long now = System.currentTimeMillis();
Date date = new Date(now);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间:" + sdf.format(date));
4. 生成唯一 ID(简单场景)
String uniqueId = System.currentTimeMillis() + "-" + Thread.currentThread().getId();
System.out.println("简单唯一ID:" + uniqueId);
四、使用技巧
1. 高频计时建议使用 System.nanoTime()
// 更精确的纳秒级计时(适合微基准测试)
long start = System.nanoTime();
// ... 操作 ...
long durationNs = System.nanoTime() - start;
double durationMs = durationNs / 1_000_000.0;
✅
currentTimeMillis()
精度低,不适合测量 < 10ms 的操作。
2. 时间比较与超时判断
long startTime = System.currentTimeMillis();
long timeout = 5000; // 5秒超时
while (System.currentTimeMillis() - startTime < timeout) {
// 执行任务
if (taskDone()) break;
Thread.sleep(100);
}
3. 缓存时间戳避免重复调用
// ❌ 错误:多次调用导致时间不一致
if (System.currentTimeMillis() > threshold1 &&
System.currentTimeMillis() < threshold2) { ... }
// ✅ 正确:缓存时间
long now = System.currentTimeMillis();
if (now > threshold1 && now < threshold2) { ... }
五、常见错误
错误 | 说明 | 修复 |
---|---|---|
误认为绝对精确 | 受系统时钟漂移、NTP 调整影响 | 不用于高精度同步 |
用于测量短时间间隔 | 毫秒级精度,可能为 0 | 改用 System.nanoTime() |
忽略时区转换 | 直接打印时间戳无意义 | 配合 Date /SimpleDateFormat 或 java.time 转换 |
用作唯一 ID 风险 | 同一毫秒内可能重复 | 加随机数或序列号:timestamp + "-" + counter |
六、注意事项
- 不是实时时钟:返回的是系统时钟,若用户手动修改系统时间,结果会跳变。
- 单调性不保证:可能因 NTP 同步出现“时间回拨”(time warp)。
- 精度限制:大多数操作系统精度为 10~16ms,不适合微秒/纳秒级测量。
- 线程安全:方法本身线程安全,但用于多线程计时时需注意共享变量。
- 未来趋势:Java 8+ 推荐使用
java.time
包(如Instant.now().toEpochMilli()
)。
七、最佳实践
✅ 推荐做法:
- 用于粗略计时(>10ms 操作)。
- 获取当前时间戳用于日志记录、缓存过期判断。
- 与
Date
配合显示可读时间。 - 在非高精度场景下生成时间相关 ID。
- 优先使用
java.time.Instant
(Java 8+)替代。
❌ 避免做法:
- 用于高精度性能分析。
- 作为分布式系统唯一 ID 主键。
- 依赖其单调递增性(如事件排序)。
- 在多线程中频繁调用且不做同步。
八、性能优化建议
优化点 | 说明 |
---|---|
✅ 调用开销极低 | currentTimeMillis() 是本地方法,调用非常快 |
✅ 无需缓存(单次) | 单次调用无需优化 |
⚠️ 高频调用注意 | 若每秒调用数万次,可考虑缓存最近时间(如“时间轮”) |
✅ 优先使用 nanoTime() 测性能 |
更适合基准测试 |
✅ 使用 java.time 替代旧 API |
更现代、更安全 |
示例:缓存时间(高频场景)
public class CachedTime {
private static volatile long currentTimeMillis = System.currentTimeMillis();
public static void update() {
currentTimeMillis = System.currentTimeMillis();
}
public static long now() {
return currentTimeMillis;
}
// 后台线程每10ms更新一次
}
适用于日志时间戳等高频但精度要求不高的场景。
九、与现代时间 API 对比(Java 8+)
方法 | 优点 | 推荐场景 |
---|---|---|
System.currentTimeMillis() |
简单、兼容老版本 | 兼容性要求高、简单计时 |
Instant.now().toEpochMilli() |
属于 java.time ,不可变、线程安全 |
Java 8+ 项目推荐 |
System.nanoTime() |
高精度、单调递增 | 性能测量、延迟计算 |
推荐写法(Java 8+):
// ✅ 推荐:使用 java.time
long timestamp = Instant.now().toEpochMilli();
// ✅ 高精度计时
long start = System.nanoTime();
// ...
十、总结
项目 | 要点 |
---|---|
本质 | 返回自 1970-01-01T00:00:00Z 起的毫秒数 |
用途 | 获取时间戳、简单计时、日志记录 |
精度 | 毫秒级,受系统时钟影响 |
优势 | 简单、高效、广泛支持 |
局限 | 精度低、非单调、不推荐用于高精度场景 |
替代方案 | Instant.now() (Java 8+)、System.nanoTime() (计时) |
关键建议 | 计时用 nanoTime ,时间戳用 Instant ,老项目可用 currentTimeMillis |
✅ 一句话总结:
System.currentTimeMillis()
是 Java 最基础的时间获取方法,适合简单场景和兼容老代码,但在 Java 8+ 环境中,应优先使用 java.time.Instant
获取时间戳,使用 System.nanoTime()
进行高精度计时。