You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SimpleDateFormat解析日期随机抛出空字符串NumberFormatException异常

问题核心原因

SimpleDateFormat 是线程不安全类,只要你将该实例作为类的成员变量、静态变量或单例对象在多线程环境下共享,多个线程同时调用parse方法时会并发修改其内部的Calendar、DigitList等共享属性,就会出现你遇到的随机非必现异常:

  • 输入的日期格式完全正常但随机报错
  • 单步调试、表达式求值时因为是单线程执行无并发冲突,所以能正常返回结果
  • 异常栈中出现的digitList值异常、Long.parseLong收到空字符串,都是共享属性被其他线程篡改后的中间值

关于JDK版本差异的疑问

JDK 1.8.0_261和1.8.0_291版本对SimpleDateFormat的核心解析逻辑没有做兼容性变更,你本地未复现、远程复现的差异大概率是本地测试时并发量低未触发并发修改冲突,远程服务并发量更高更容易触发问题,和版本无关。

解决方案

你可以根据业务场景选择以下任意一种方案修复:

  • 每次调用解析逻辑时单独创建SimpleDateFormat实例,不做全局共享,并发量较低的场景可直接使用
  • 用ThreadLocal封装SimpleDateFormat,保证每个线程持有独立的实例,避免并发修改,示例代码:
private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT_THREAD_LOCAL = 
    ThreadLocal.withInitial(() -> new SimpleDateFormat("dd/MM/yyyy", Locale.US));

// 调用时使用
return DATE_FORMAT_THREAD_LOCAL.get().parse((String)properties.get("validfrom"));
  • (推荐)JDK8及以上版本直接使用java.time包下的线程安全类DateTimeFormatter替换SimpleDateFormat,彻底避免线程安全问题,示例代码:
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy", Locale.US);

// 解析时使用
LocalDate localDate = LocalDate.parse((String)properties.get("validfrom"), DATE_FORMATTER);
// 如需转Date对象可按以下逻辑转换
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());

内容的提问来源于stack exchange,提问作者hovibi9445

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 08:54:05