在 Java 开发中,SimpleDateFormat 是线程不安全的。若将其定义为 static 变量,在多线程环境下极易引发解析错误或格式化异常(如 NumberFormatException)。因此,禁止直接将 SimpleDateFormat 声明为 static。
安全替代方案有三:
- 使用 Apache Commons Lang 的
DateUtils,其内部已处理线程安全; - 通过
ThreadLocal封装,确保每个线程拥有独立实例:
private static final ThreadLocal<DateFormat> df = ThreadLocal.withInitial( () -> new SimpleDateFormat("yyyy-MM-dd") );
- JDK 8+ 推荐使用新的日期时间 API:
- 用
LocalDateTime替代Calendar, - 用
DateTimeFormatter替代SimpleDateFormat。
后者是不可变(immutable)且线程安全的,官方评价其“simple, beautiful, strong, immutable, thread-safe”。
并发修改同一记录需加锁
当多个请求可能同时修改同一条数据时,必须引入并发控制机制,否则会导致数据覆盖或状态错乱。
常见策略包括:
- 应用层加锁(如
synchronized或ReentrantLock); - 缓存层加锁(如 Redis 分布式锁);
- 数据库层使用乐观锁:通过
version字段控制更新,SQL 示例:
UPDATE table SET value = ?, version = version + 1 WHERE id = ? AND version = #{oldVersion}
选择建议:
- 若冲突概率 < 20%,优先用乐观锁(性能更高);
- 否则使用悲观锁(如数据库行锁);
- 乐观锁重试次数不应少于 3 次,以应对短暂竞争。
总结
- 日期格式化:弃用
static SimpleDateFormat,拥抱DateTimeFormatter或ThreadLocal; - 并发写入:根据冲突频率选择乐观/悲观锁,确保数据一致性。
这两点虽小,却是高并发系统稳定性的基石。