【问题标题】:Can we declare SimpleDateFormat objects as static objects我们可以将 SimpleDateFormat 对象声明为静态对象吗
【发布时间】:2016-04-21 16:56:47
【问题描述】:
SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM");
SimpleDateFormat fullFormat = new SimpleDateFormat("EE MMM dd, HH:mm:ss")

我有几段这样的代码经常被调用,将它们声明为static 变量是否有意义?

在这种情况下将动态参数传递给format() 方法是否线程安全?

【问题讨论】:

    标签: java thread-safety simpledateformat


    【解决方案1】:

    它们不是线程安全的。请改用Joda-time's version

    或者将它们封装在同步方法中并使其成为线程安全的

    Doc说清楚了

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

    【讨论】:

    • 在我看来,同步是一种非常次优的方式。临界区应始终是您的最后手段,并且仅用于必须是全局唯一且线程安全的对象。使用线程本地。为每个新线程创建一次 SimpleDateFormat 的成本将可靠地超过同步成本,无论是在性能还是复杂性方面。
    • 大多数开发人员都明白,对于大多数非线程安全的类,这是由于同时更改状态所致。建立格式后,格式化日期不应更改状态。仅在官方文档中将其记录为不是线程安全的是不够的。应该明确记录,如果格式方法在实例变量中保持临时状态,那么它也不是线程安全的。将其声明为静态不仅仅是一个新手错误。可以在修改集合 (put) 与访问集合 (get) 之间进行类比。
    【解决方案2】:

    从 Java 8 开始,新的 Date API 支持此功能。 DateTimeFormatter 是线程安全的,可以做与SimpleDateFormat 相同的工作。引用自 JavaDoc:

    从模式创建的格式化程序可以根据需要多次使用,它是不可变的并且是线程安全的。

    为了更加清楚,定义如下格式是完全可以的:

    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
    

    并且在可以被多个线程同时访问的方法中使用:

    String text = date.toString(formatter);
    LocalDate date = LocalDate.parse(text, formatter);
    

    【讨论】:

      【解决方案3】:

      DateFormat 不是线程安全的。如果多个线程在没有任何同步的情况下使用相同的 DateFormat 对象,您可能会得到意想不到的结果。因此,您应该同步对 DateFormat 对象的访问、使用 ThreadLocal 变量或使用替代的 Date API,例如 Joda-Time。

      有关如何执行此操作的更多信息,请查看此博客文章:DateFormat with Multiple Threads

      【讨论】:

        【解决方案4】:

        【讨论】:

          【解决方案5】:

          静态应该不是问题。

          由于 AFAIK 无法保证线程安全,因此您必须检查源代码。即使您得出它是线程安全的结论,这也可能会随着下一个版本而改变。 正如另一个答案中所说,它们不是线程安全的。

          你真的分配了这么多线程,给每个线程自己的格式是个问题吗?

          【讨论】:

          • javadoc 说它不是线程安全的,所以让它成为静态是一个很大的禁忌。
          • 这可能会导致依赖格式化日期输出的业务应用程序出现严重错误。可能日期可能完全或部分混淆。因此没有好的建议!
          • @user326120 什么可以混淆日期?
          • @JensSchauder 并发访问 DateFormat.format 将返回混合日期,假设 DateFormat df = ...;线程 1 带有 df.format(d1),然后线程 2 带有 df.format(d2),而线程 1 仍在执行 df.format(d1)。 - 结果无法预测,因为 DateFormat 是可变的,否则它将是线程安全的。 (您可以编写一个小型测试程序,创建 10000 个线程同时通过一个 DateFormat 实例输出格式化日期,而日期必须在日(月)和年中有所不同,因此您可以分辨“混合”。探索它并告诉我们结果!)
          • @Andreas Krueger 没有人说你应该同时访问它。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-15
          • 2015-09-18
          • 2019-09-16
          相关资源
          最近更新 更多