【问题标题】:Java: Synchronization issue with NumberFormat?Java:NumberFormat 的同步问题?
【发布时间】:2010-11-20 02:15:31
【问题描述】:

我使用 java.text.NumberFormat 只是为了将数字转换为更易读的字符串,用逗号分隔千位等。基本上我将其定义为:

public static NumberFormat nf = NumberFormat.getInstance(Locale.US);

...然后我只需在我想要制作数字的可读版本的任何线程中调用 nf.format(some_number) 。但是查看JavaDoc,它说:“数字格式一般是不同步的。建议为每个线程创建单独的格式实例。如果多个线程同时访问一个格式,则必须在外部同步。”

如果我只使用 NumberFormat 对象的 format(number) 方法,会不会出现同步问题?我尝试使用 NumberFormat.getInstance(Locale.US).format(number) 代替,但每次我觉得可能并不真正需要这样做时都会产生相关的开销。这真的需要外部同步吗?或者有没有一种更简单、更有效的方法来完成同样的事情而无需 NumberFormat?

谢谢!

【问题讨论】:

    标签: java


    【解决方案1】:

    即使 format 是您调用的唯一方法,它仍然不是线程安全的。事实上,由于这个原因,我们在工作中遇到了错误。我们通常要么动态创建 NumberFormat 对象,要么按照 Gerco 的建议使用 ThreadLocal。如果你想变得花哨,你可以继承 NumberFormat 并在 format 方法中,要么在委托 NumberFormat 上调用 format 之前同步,要么使用 ThreadLocal 来检索委托。

    但是,我认为最直接的方法是手动使用 ThreadLocal,尤其是如果您要连续格式化/解析多个数字。

    【讨论】:

    【解决方案2】:

    使用 ThreadLocal。这样,每个线程都将拥有自己的私有 NumberFormat 实例,并且无需同步且开销最小。

    【讨论】:

      【解决方案3】:

      查看NumberFormatDecimalFormat 的源代码,似乎没有用于中间结果的任何字段 - 唯一的问题是格式本身(例如小数位数)通过设置器是可变的,因此一个线程可以在另一个线程的format() 调用正在处理时更改它,这当然会导致混乱。

      如果您从不使用 setter,那么 应该 没问题 - 当然这只是当前的实现。依赖于与 API 文档相反的内容,我会感到不舒服。使用ThreadLocal 听起来是个不错的折衷方案。

      【讨论】:

      • 我知道这是一个旧答案,但是......你真的不应该去源代码。即使您知道您使用的是什么版本的 Java,供应商之间也有所不同。 (例如,我已经看到 IBM 和 Sun/Oracle JVM 之间的许多差异。)
      • 在我的 JDK 版本中,实际上存储了中间结果,但正如你所说的 YMMV。
      【解决方案4】:

      NumberFormat 是一个abstract class。调用getInstance 时的默认设置是返回DecimalFormat 的实例。 DecimalFormat 使用一堆字段来保持其在格式化过程中的位置,前缀和后缀的模式,booleans 指示是否使用指数符号和千位分组,ints 来描述其整数的大小和分数部分等。

      如果您期望任何并发格式,ThreadLocal 选项是一个很好的选择。请注意,abstractFormat 类的所有子类都被认为不是线程安全的,因此也应该非常小心地处理格式化日期。

      【讨论】:

        【解决方案5】:

        没有理由共享 NumberFormat 对象。是的,它可能存在同步问题(查看您的语言环境的源代码,您会发现它们使用成员变量,甚至格式化)。在您遇到性能问题(您很可能不会)之前,只需为每次使用创建一个新问题。

        编辑 正如 Michael Borgwardt 所指出的,我对成员变量的预感是不正确的。不过,何必担心呢?使用 LocalThread,克隆 NumberFormat,或者只是制作一个新的。 大多数时候(但并非总是),对象创建方面的效率并不是真正的问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-09-25
          • 1970-01-01
          • 1970-01-01
          • 2012-07-08
          • 2011-07-15
          • 2015-05-03
          • 2012-11-01
          相关资源
          最近更新 更多