news 2026/1/30 0:00:19

SimpleDateFormat 为什么线程不安全

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SimpleDateFormat 为什么线程不安全

SimpleDateFormat线程不安全的,主要原因如下:

1.内部状态可变性

// SimpleDateFormat 内部维护了可变状态 private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // 会修改内部的 Calendar 对象 calendar.setTime(date); // ... }

2.共享的 Calendar 实例

每个SimpleDateFormat对象内部都持有一个Calendar实例:

public class SimpleDateFormat extends DateFormat { protected Calendar calendar; // 共享的可变状态 public String format(Date date) { // 1. 设置时间到 calendar calendar.setTime(date); // 2. 使用 calendar 进行格式化 return format(calendar); } }

3.并发问题场景

情况1:多线程同时调用 format()

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // 线程A sdf.format(dateA); // 设置 calendar 为 dateA // 线程B在此刻插入 sdf.format(dateB); // 设置 calendar 为 dateB // 线程A继续格式化,但calendar已经被线程B修改

情况2:多线程同时调用 parse()

// 线程A sdf.parse("2024-01-01"); // 线程B sdf.parse("2024-02-01"); // 两者可能互相干扰,得到错误结果

4.问题复现代码

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ExecutorService executor = Executors.newFixedThreadPool(10); List<Future<String>> futures = new ArrayList<>(); for (int i = 0; i < 10; i++) { final int index = i; futures.add(executor.submit(() -> { Date date = new Date(System.currentTimeMillis() + index * 1000); return sdf.format(date); // 可能出现:空指针、格式错误、时间错乱 })); }

5.线程安全的替代方案

方案1:使用 ThreadLocal(推荐)

private static final ThreadLocal<SimpleDateFormat> threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd")); public String formatDate(Date date) { return threadLocal.get().format(date); }

方案2:每次创建新实例

public String formatDate(Date date) { return new SimpleDateFormat("yyyy-MM-dd").format(date); } // 缺点:频繁创建对象,性能较差

方案3:使用 DateTimeFormatter(Java 8+)

// DateTimeFormatter 是线程安全的 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 格式化 String formatted = LocalDateTime.now().format(formatter); // 解析 LocalDateTime parsed = LocalDateTime.parse("2024-01-26 10:30:00", formatter);

方案4:使用 FastDateFormat(Apache Commons Lang)

FastDateFormat formatter = FastDateFormat.getInstance("yyyy-MM-dd"); String formatted = formatter.format(new Date()); // 线程安全

6.为什么 DateTimeFormatter 线程安全?

public final class DateTimeFormatter { // 所有字段都是 final 的 private final CompositePrinter printer; private final CompositeParser parser; private final Locale locale; // 所有方法都是纯函数,不修改内部状态 public String format(TemporalAccessor temporal) { // 不修改任何实例变量 } }

总结

  • 根本原因SimpleDateFormat内部可变状态(Calendar)在多线程下被共享修改

  • 解决方案

    1. 使用ThreadLocal包装(适合传统项目)

    2. 使用 Java 8+ 的DateTimeFormatter(推荐新项目)

    3. 使用同步锁(性能差,不推荐)

在并发环境下,永远不要共享同一个SimpleDateFormat实例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/28 11:12:18

轨道小车无线控制系统设计与实现

在汽车制造、仓储物流、冶金化工等场景中&#xff0c;轨道小车是物料转运的“动脉”&#xff0c;其控制精度与运行效率直接影响生产节拍与成本。然而&#xff0c;传统有线控制模式面临布线复杂、维护成本高、移动受限等痛点&#xff0c;拖链电缆频繁弯折导致断裂、信号衰减&…

作者头像 李华
网站建设 2026/1/26 21:49:08

三菱PLC 与组态王打造变频器恒压供水系统控制

三菱PLC和组态王组态变频器的恒压供水系统控制在工业自动化领域&#xff0c;恒压供水系统是保障稳定供水的关键技术。今天咱们就来聊聊如何用三菱 PLC 和组态王来实现变频器的恒压供水系统控制。 一、系统架构 恒压供水系统主要由水泵、变频器、压力传感器、三菱 PLC 和组态王软…

作者头像 李华
网站建设 2026/1/29 6:49:53

探索MD500E伺服驱动器代码的奇妙世界

伺服驱动器资料 md500e代码 MD500E代码方案和解析文档原理图送仿真资料。 包含pmsm的foc控制算法&#xff0c;电阻、电感、磁链等参数的辩识算法&#xff0c;死区补偿算法过调制处理算法&#xff0c;弱磁控制算法&#xff0c;无感FOC控制算法&#xff0c;电流环自整定算法&…

作者头像 李华
网站建设 2026/1/29 9:07:10

Ubuntu 24 通关 MySQL:从本地安装到 root 远程登录的一站式实操指南

本文针对 Ubuntu 24.04 LTS 系统,整理了一套从 MySQL 安装到 root 用户远程登录授权的完整有序步骤,所有代码均可直接复制执行,解决新手常见的安装配置与远程连接痛点。 步骤 1:前置准备 - 更新系统包索引 安装前先更新本地包列表,避免因依赖版本过旧导致安装失败。 su…

作者头像 李华
网站建设 2026/1/28 21:39:26

如何绑定自己的域名生成专属短链接

将自有域名解析至C1N短链接(c1n.cn)平台&#xff0c;生成自有域名下的短链接&#xff0c;可以让链接更具品牌辨识度。 ​ 大家经常需要将长链接转为短链接&#xff0c;方便推广传播。但很多时候又想用自己的域名生成短链接&#xff1f; 搭建短链接平台比较麻烦&#xff0c;C1N …

作者头像 李华