【问题标题】:Strange ArrayIndexOutOfBoundsException for Java SimpleDateFormatJava SimpleDateFormat 的奇怪 ArrayIndexOutOfBoundsException
【发布时间】:2013-08-25 08:23:08
【问题描述】:

我们运行 Java 1.4。

我们有这个方法:

static SimpleDateFormat xmlFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

public static Date fromXml(String xmlDateTime) {
    ParsePosition pp = new ParsePosition(0);
    return xmlFormatter.parse(xmlDateTime, pp);
}

例如xmlDateTime = 2013-08-22T16:03:00。这一直有效,但突然停止了!

我们现在得到这个异常:

java.lang.ArrayIndexOutOfBoundsException: -1
at java.text.DigitList.fitsIntoLong(DigitList.java:170)
at java.text.DecimalFormat.parse(DecimalFormat.java:1064)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1381)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1159) 

我试图通过使用不同的日期格式在单元测试中重现这一点,即:

2013-08-22T16:03:00
2013-08-22 16:03:00

但没有运气!有什么想法吗?

【问题讨论】:

    标签: java simpledateformat indexoutofboundsexception


    【解决方案1】:

    SimpleDateFormat不是线程安全的是一个鲜为人知的事实!

    不是一个错误:javadoc 记录了这种行为:

    日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一个格式,必须在外部同步。

    每次需要时创建一个实例,或者如果性能是一个真正的问题,您可以尝试使用ThreadLocal 为每个需要的线程存储一个实例。


    别难过:我完全喜欢这种“优化”(重用单个常量实例),令我惊讶的是,每次都必须实例化一个新实例。

    【讨论】:

    • 当存在joda-time 库时,可以使用DateTimeFormat。它是不可变的,因此像 joda-time 中的所有东西一样是线程安全的。顺便说一句 +1
    • 我在 Android 上遇到了同样的问题,但格式化了日期。它怎么可能不是线程安全的?在我看来,它内部应该有一个非常通用的算法,不需要假设任何关于线程的事情......
    • @android 它不是线程安全的,因为编写它的白痴决定不让它成为线程安全的。然而,Java 8 的 DateTimeFormatter线程安全的。
    • @Bohemian 遗憾的是,Java 8 在 Android 上还处于非常早期的阶段。我将使用克隆为每个线程创建一个新实例。
    【解决方案2】:

    看起来像this bug report。根本原因被诊断为 DecimalFormat 根本不是线程安全的。

    所以你不应该在不同的线程上使用相同的SimpleDateFormat 实例,因为它和DecimalFormat 仍然不是线程安全的。

    您可以使用ThreadLocal 让每个线程使用自己的实例。

    【讨论】:

    • 看起来那个 bug 只影响 Java 3。
    • 该链接有点误导,因为阅读您的答案的人认为您在说这是一个错误。这不是一个错误。我建议删除带有链接的句子。
    • 解决方案是让 DecimalFormat 线程安全,它仍然不在 Java 7 中,所以我猜即使在现代 JDK 上也会发生这种行为。
    • @FabianBarney 澄清了链接的用处。
    【解决方案3】:

    尝试使用 Commons Lang 3.x FastDateParser 和 FastDateFormat。这些类是线程安全的,并且比 SimpleDateFormat 更快。它们还支持与 SimpleDateFormat 相同的格式/解析模式规范。

    【讨论】:

    • 今天这对我帮助很大。谢谢你!
    【解决方案4】:

    每次创建实例的简单方法,本地/范围变量而不是全局变量,它适用于我

    private void test {
        SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(pattern, Locale.ENGLISH);
        // Do somethings
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-25
      • 1970-01-01
      • 1970-01-01
      • 2016-08-30
      • 2011-01-06
      • 1970-01-01
      相关资源
      最近更新 更多