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

【Java踩坑笔记】47_日期时间计算还在用SimpleDateFormat?线程不安全

47 | 日期时间计算还在用 SimpleDateFormat?线程不安全

摘要SimpleDateFormat不是线程安全的,多线程共享一个实例会导致数据错乱甚至抛异常。Java 8+ 用DateTimeFormatter(不可变,线程安全)。


一、问题现象

// ❌ 多线程共享 SimpleDateFormat,数据错乱privatestaticfinalSimpleDateFormatFMT=newSimpleDateFormat("yyyy-MM-dd");publicstaticvoidmain(String[]args){for(inti=0;i<10;i++){newThread(()->{try{System.out.println(FMT.parse("2024-01-01"));}catch(Exceptione){e.printStackTrace();// ❌ 多线程下可能抛异常}}).start();}}

现象:偶尔出现NumberFormatException或解析出错误日期。


二、踩坑现场

场景:Web 项目里共用 SimpleDateFormat

// ❌ 错误:定义为静态字段(多线程共享)@ComponentpublicclassDateService{privatestaticfinalSimpleDateFormatFMT=newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");publicStringformat(Datedate){returnFMT.format(date);// ❌ 多线程并发,结果错乱}}

结果:并发请求下,格式化结果出现错乱日期。


三、原理解析

3.1 为什么线程不安全?

SimpleDateFormat内部用Calendar实例做计算,而Calendar是可变对象:

线程 A:fmt.format(date1) → 修改内部 calendar 字段 线程 B:fmt.format(date2) → 同时修改同一个 calendar → 数据竞争,结果不可预测

3.2 三种错误用法对比

用法问题
静态字段(共用)❌ 线程不安全
每次创建新实例⚠️ 性能差(频繁创建对象)
synchronized⚠️ 并发性能差

四、正确写法

4.1 Java 8+:用DateTimeFormatter(推荐)

// ✅ 不可变,线程安全privatestaticfinalDateTimeFormatterFMT=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");publicStringformat(LocalDateTimetime){returntime.format(FMT);// ✅ 线程安全}

4.2 Java 7-:用ThreadLocal缓存

// ✅ 每个线程有自己的 SimpleDateFormat 实例privatestaticfinalThreadLocal<SimpleDateFormat>FMT_HOLDER=ThreadLocal.withInitial(()->newSimpleDateFormat("yyyy-MM-dd"));publicStringformat(Datedate){returnFMT_HOLDER.get().format(date);}

4.3 需要 Date ↔ LocalDateTime 互转

// ✅ Java 8+ 互转Datedate=newDate();LocalDateTimetime=date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();LocalDateTimenow=LocalDateTime.now();Datedate2=Date.from(now.atZone(ZoneId.systemDefault()).toInstant());

五、最佳实践

✅ 日期时间处理的 4 条铁律

  1. Java 8+ 全面用java.time包(LocalDateLocalDateTimeDateTimeFormatter
  2. SimpleDateFormat不是线程安全的,不要定义为静态字段
  3. 老代码迁移DateInstantCalendarLocalDateTime**
  4. 时区处理用ZoneId,不要用TimeZone**

🔍java.time包的优势

替换优势
LocalDateDate只有日期,不可变,线程安全
LocalDateTimeCalendar日期+时间,不可变
DateTimeFormatterSimpleDateFormat不可变,线程安全
InstantDate时间戳,时区无关

六、小结

  • SimpleDateFormat不是线程安全的,静态共用会数据错乱
  • Java 8+ 用DateTimeFormatter,不可变,线程安全
  • 老代码用ThreadLocal<SimpleDateFormat>缓存每个线程的实例
  • java.time包全面替换Date/Calendar,不可变且 API 更友好

下一篇预告:用 Optional 消灭 NPE,但别把它当万能药——Optional的设计目的是减少 NPE,但滥用反而让代码更难读。

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

相关文章:

  • 2026六安楼顶漏水、卫生间漏水、外墙、地下室、阳台渗漏不用愁!3家口碑服务商(7月) - 防水企业百科
  • 【SpringAI 10】对话机器人快速入门
  • 社交媒体危机公关:从品牌营销边界到舆情管理实战
  • 2026临沂楼顶漏水、卫生间漏水、外墙、地下室、阳台+阳光房渗漏不用愁!3家靠谱公司(7月) - 防水企业百科
  • 武汉爱彼回收价格查询和靠谱平台实测排行(2026年7月最新) - 诚收名表回收平台
  • 亲测义乌1688代入驻,2026复盘分享 - 花开富贵112
  • LTC4417IUF#TRPBF是一款36V 工业级防反灌电源控制器
  • RTX5090 32G 八卡算力集群技术特性与全行业落地应用场景详解
  • Python agent-eval 包详解:功能、安装、语法与实战案例
  • 从g到ODR:深入解读加速度传感器关键参数与选型指南
  • 安卓15_ROM修改定制化_____修改设置菜单中的中文名称
  • 计算机毕业设计之jsp球鞋商城系统
  • 2026暑假一家三口去新疆旅游需要多少钱?真实预算明细+避坑攻略 - 旅行分享
  • 现代C++ TOML解析器toml++:从使用到贡献代码的完整指南
  • 杭州欧米茄回收价格查询及靠谱回收平台实测排行(2026年7月最新) - 天价名表回收平台
  • 2026北京卫生间漏水、外墙、楼顶、地下室渗漏怎么办?3家正规防水公司推荐(7月) - 防水企业百科
  • 2026 年|杭州定制化家居服务企业做GEO服务商哪个好?本地服务商实力排名与选型指南 - 企业新闻快传
  • 鸿蒙ArkUI实战:建立浅色与深色主题的颜色映射
  • 杭州GEO公司哪家好?中小企业入门级GEO服务商TOP6推荐 - 资讯纵览
  • 基于STM32单片机汽车电动车RFID刷卡充电扣费TFT彩屏设计DIY-T135
  • 电脑屏幕共享给手机怎么操作 电脑屏幕共享给手机的软件
  • 2026黄冈外墙渗漏、卫生间漏水、楼顶、地下室、阳台渗漏?3家靠谱服务商测评(7月) - 防水企业百科
  • 鸿蒙 AI 自动化开发:让 AI 学会自己编译、自己调试
  • STM32F103实战:USB虚拟串口(CDC)的配置、调试与性能优化
  • 基于libqrencode的C++二维码生成库:从原理到嵌入式实践
  • 为什么程序员不再只用 GPT-4?多模型协作怎么选?2026最新选型攻略与避坑盘点
  • 【LE Audio】CSIS精讲[2]: 服务核心运作逻辑
  • 2026年GEO服务商实力横评:答序科技综合测评位列第一,全栈自研与闭环交付能力断层领先 - 天涯视角
  • 【数据结构与算法 | 第一篇】时间复杂度和空间复杂度
  • 烟台SEO优化公司|长尾词矩阵建设,烟台SEO全案外包服务商解读 - 招财兔数字员工