Date、Calendar、SimpleDateFormat 非线程安全,因其内部状态可变且无同步控制;Java 8 的 LocalDate 等不可变类通过返回新对象、final 字段实现线程安全。

因为它们内部状态可变,且没有同步控制。
核心问题在于可变性
Date 类本身是可变的——它的毫秒值可以通过 setTime() 直接修改;Calendar 更明显,它内部维护一个完整的日历字段集合(年、月、日、时、分、秒等),所有 get() 和 set() 操作都读写同一块内存状态。多个线程同时调用 calendar.add(Calendar.DAY_OF_MONTH, 1) 或 calendar.setTime(date),结果无法预期。
SimpleDateFormat 是典型触发点
它虽不是 Date 或 Calendar 本身,但深度依赖 Calendar:
-
parse()先调用calendar.clear(),再逐个set()字段,中间状态可能被其他线程打断 -
format()同样先设时间再填充字段,若线程 A 刚设完年份、线程 B 就读取,可能拿到 “2026-00-00” 这类非法值 - 其内部
calendar字段未加 volatile、未用锁保护,也非原子操作
设计上缺乏并发意识
这些类诞生于 JDK 1.0–1.1 时期,当时多线程并非主流开发场景:
- 没有将关键字段声明为
final - 没有提供不可变副本或线程隔离机制
- API 方法不承诺线程安全,文档也未明确警示
对比 Java 8 的解决思路
LocalDate、LocalDateTime 等类全部是 final 且不可变的:
- 所有“修改”方法(如
plusDays())都返回新对象,原实例不变 - 内部字段全为
private final,构造后无法更改 - 可放心定义为
static final,多线程共享无风险

















