当前位置: 首页 > news >正文

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实例

http://www.jsqmd.com/news/304800/

相关文章:

  • 【Rust开发】Rust基础语法详细解析,助力你快速通关Rust
  • 性能优化:类型系统的最佳实践
  • 设计模式在 TypeScript 中的实现
  • 2026年1月线切割机床厂家推荐排行榜,中走丝/快走丝/电火花线切割机床,穿孔机,精密高效加工设备源头厂商精选
  • C盘爆红怎么办!几招彻底清理电脑C盘空间
  • 研发需求排期实战指南:工具选型、流程搭建与效能提升
  • 聊聊AI智能客服
  • 破解协作低效难题:中小企业流程数字化工具及核心策略
  • 测试用例执行进度实时同步工具指南:从流程打通到效率提效的全链路落地
  • 【无人机追踪】基于资源福利任务分配算法的无人机集群任务分配算法,完成目标攻击任务的基础上,无人机的资源利用率最大化 + 资源损耗的公平性最优附Matlab代码2
  • 2026年铝板厂家推荐排行榜:幕墙铝板、氟碳铝板、木纹铝板、蜂窝铝板、异型铝板等全品类实力厂家深度解析与选购指南
  • RAG 不是万能解,这些场景你一开始就不该用
  • 零基础想转行网络安全?这3个方向门槛低、就业快
  • 运维人别内耗!转行网安,薪资翻倍+职业逆袭指南
  • 2026网络安全这趟车_你还敢上吗?
  • 2026年,还能继续入网络安全行业吗?那些行业不敢说的秘密
  • 普通本科转行网络安全5年,现在月薪2W+,劝你想清楚!
  • IP6163至为芯支持MPPT功能的太阳能电池板充电DC-DC芯片
  • 轨道小车无线控制系统设计与实现
  • 【图像加密】基于DCT变换的图像加密与解密附matlab代码
  • 2026年想给Facebook广告账户充值,到底该找谁?这里有一份详细的避坑指南
  • 144. 二叉树的前序遍历-day11
  • 2026年 电机厂家推荐排行榜:直驱电机/线性电机/无框电机/力矩电机/高频电机,核心技术与高效能解决方案深度解析
  • Comsol电弧冲击击穿模型:多相流模拟的奇妙之旅
  • 交流调压那些事儿:单相、三相及带中性线三相交流调压
  • 探索锂电池生产设备的自动化控制:从硬件到软件实现
  • 探索基于SPWM的异步电机无速度传感器矢量控制
  • 【路径规划】基于Bi-RRT算法实现机器人路径规划实现,最终找到一条无碰撞路径附matlab代码
  • 《神经光栅无缝融合指南:底层逻辑与落地方法》
  • 《程序化内容生成可控性与随机性平衡实操指南》