news 2026/6/15 9:06:01

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/6/15 15:04:13

普通本科转行网络安全5年,现在月薪2W+,劝你想清楚!

【收藏级】网络安全自学指南&#xff1a;零基础到实战的完整路径&#xff0c;少走弯路必备 这是一位有五年网络安全经验的从业者分享的入门指南。作者强调行业缺的是能解决问题的人&#xff0c;而非只会背理论的人。文章从零基础到进阶&#xff0c;推荐了多个学习资源&#xf…

作者头像 李华
网站建设 2026/6/15 18:42:46

产品需求池管理工具实践指南:从需求汇聚到落地闭环的全维度管控

在产品研发全生命周期中&#xff0c;需求管理是产品工作的起点与核心&#xff0c;而产品需求池则是所有需求的“统一入口”与“管理中枢”。从客户反馈、业务诉求到用户建议、内部创意&#xff0c;各类需求杂乱分散的问题&#xff0c;往往导致需求遗漏、优先级混乱、落地无追踪…

作者头像 李华
网站建设 2026/6/15 15:15:39

西门子1200伺服步进FB块程序揭秘

西门子1200伺服步进FB块程序 &#xff0c;一共两个FB&#xff0c;一个是scl写的&#xff0c;一个是梯形图&#xff0c;可以多轴多次调用&#xff0c;中文注释详细&#xff0c;真实可用&#xff0c;经过在专用设备真实调试运行&#xff0c;可以直接应用到实际项目中&#xff0c;…

作者头像 李华
网站建设 2026/6/15 13:35:24

欧姆龙 CJ/CP 程序在全自动 CE 锂电池贴胶检测机中的应用

omron欧姆龙CJ/CP程序 欧姆龙CP1H-XA&#xff0c;主机搭载CIF串口模块与从机PC LINK通信控制&#xff0c; 全自动CE锂电池贴胶检测机&#xff0c;主从站进行轴控制&#xff0c;涵盖人机配方一键换型功能&#xff0c;故障记录功能&#xff0c;产量统计及OEE功能&#xff0c;优质…

作者头像 李华
网站建设 2026/6/15 15:36:59

产业指挥棒下的重塑:职业教育政策解读与应对策略

> 一张专业清单、一份拨款系数表&#xff0c;正悄然重塑中国职业教育的基因&#xff0c;从“我能教什么”到“产业需要什么”的时代已经到来。--- 近两年&#xff0c;教育部及各地密集出台一系列职业教育新政&#xff0c;从专业设置到资金分配&#xff0c;从培养模式到评价体…

作者头像 李华
网站建设 2026/6/15 14:15:17

异构网络垂直切换算法MATLAB仿真实现

一、仿真框架设计 基于多属性决策判决算法实现异构网络垂直切换&#xff0c;支持TD-SCDMA/LTE/WiFi等网络类型&#xff0c;包含以下核心模块&#xff1a; 网络拓扑建模&#xff1a;定义基站位置、覆盖范围及用户移动路径 信号强度计算&#xff1a;基于距离衰减模型计算接收功…

作者头像 李华