Java:与 NumberFormat 的同步问题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1285279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: Synchronization issue with NumberFormat?
提问by DivideByHero
I use java.text.NumberFormat simply to convert numbers into more readable Strings, with commas separating thousands, etc. Basically I define it as:
我使用 java.text.NumberFormat 只是将数字转换为更易读的字符串,用逗号分隔千位等。基本上我将其定义为:
public static NumberFormat nf = NumberFormat.getInstance(Locale.US);
...and then I just call nf.format(some_number) in any thread where I want to make a readable version of a number. But looking at the JavaDoc, it says: "Number formats are generally not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally."
...然后我只是在我想要制作数字的可读版本的任何线程中调用 nf.format(some_number) 。但是查看JavaDoc,它说:“数字格式通常不同步。建议为每个线程创建单独的格式实例。如果多个线程并发访问一种格式,则必须在外部进行同步。”
If I am only using the format(number) method of the NumberFormat object, could there ever be a synchronization issue? I tried using NumberFormat.getInstance(Locale.US).format(number) instead, but there is overhead associated with doing that every time that I feel is probably not really needed. Does this really need external synchronization? Or is there a simpler, efficient way of accomplishing the same thing without NumberFormat?
如果我只使用 NumberFormat 对象的 format(number) 方法,是否会出现同步问题?我尝试使用 NumberFormat.getInstance(Locale.US).format(number) 代替,但是每次我觉得可能不是真的需要这样做时都会产生相关的开销。这真的需要外部同步吗?或者有没有更简单、有效的方法来完成同样的事情而不使用 NumberFormat?
Thanks!
谢谢!
回答by Adam Crume
Even if format is the only method you ever call, it's still not thread-safe. In fact, we've had bugs at work due to this. We usually either create NumberFormat objects on the fly, or use a ThreadLocal as Gerco suggested. If you wanted to get fancy, you could subclass NumberFormat and in the format method, either synchronize before calling format on a delegate NumberFormat or use a ThreadLocal to retrieve a delegate.
即使 format 是您调用的唯一方法,它仍然不是线程安全的。事实上,由于这个原因,我们在工作中遇到了错误。我们通常要么动态创建 NumberFormat 对象,要么使用 Gerco 建议的 ThreadLocal。如果你想变得更有趣,你可以子类化 NumberFormat 并在 format 方法中,要么在调用委托 NumberFormat 上的格式之前同步,要么使用 ThreadLocal 来检索委托。
However, I believe the most straightforward way, especially if you're going to format/parse several numbers in a row, is to use a ThreadLocal manually.
但是,我相信最直接的方法,尤其是当您要连续格式化/解析多个数字时,是手动使用 ThreadLocal。
回答by Gerco Dries
Use a ThreadLocal<NumberFormat>. That way each thread will have it's own private NumberFormat instance and there will be no need to synchronise and only minimal overhead.
使用 ThreadLocal<NumberFormat>。这样每个线程都会有它自己的私有 NumberFormat 实例,并且不需要同步并且只有最小的开销。
回答by Michael Borgwardt
Looking at the source code of NumberFormatand DecimalFormat, there don't seem to be any fields used for intermediate results - the only problem is that the format itself (e.g. number of fractional digits) is mutable via setters, so one thread could change it while another's format()call is being processed, and that would of course lead to a mess.
查看NumberFormatand的源代码,DecimalFormat似乎没有任何用于中间结果的字段 - 唯一的问题是格式本身(例如小数位数)通过 setter 是可变的,因此一个线程可以更改它,而另一个线程可以更改它format()正在处理呼叫,这当然会导致混乱。
If you never use the setters, then it shouldbe OK - but of course this is only the current implementation. I wouldn't feel comfortable with depending on that contrary to the API docs. Using a ThreadLocalsounds like a good compromise.
如果您从不使用 setter,那么应该没问题——但这当然只是当前的实现。依赖于与 API 文档相反的内容,我会感到不舒服。使用 aThreadLocal听起来是一个很好的妥协。
回答by akf
NumberFormatis an abstract class. Its default when calling getInstanceis to return an instance of DecimalFormat. DecimalFormatuses a bunch of fields for maintaining its position within its formatting process, patterns for prefixes and suffixes, booleans indicating whether or not to use exponential notation and thousands grouping, ints to describe the size of its integer and fraction parts, etc.
NumberFormat是一个abstract class。调用时它的默认值getInstance是返回 的实例DecimalFormat。 DecimalFormat使用一堆字段来维护其在格式化过程中的位置,前缀和后缀的模式,booleans 指示是否使用指数表示法和千位分组,ints 来描述其整数和小数部分的大小等。
The ThreadLocaloption is a great way to go if you expect any concurrent formatting. Note that all subclasses of the abstractFormatclass are considered not thread-safe, so formatting dates should be handled with this much care as well.
ThreadLocal如果您期望任何并发格式,该选项是一个很好的选择。请注意,abstractFormat该类的所有子类都被认为不是线程安全的,因此在处理格式化日期时也应格外小心。
回答by Dan Rosenstark
There is no reason to share a NumberFormat object. Yes, it can have synchronization issues (look at the source for your locale and you will see that they use member variables, even to format). Until you have performance issues (which you most likely won't), just create a new one for each use.
没有理由共享 NumberFormat 对象。是的,它可能有同步问题(查看您的语言环境的源代码,您将看到它们使用成员变量,甚至用于格式化)。在您遇到性能问题(您很可能不会)之前,只需为每次使用创建一个新问题。
EditAs Michael Borgwardt points out, my hunch about member variables was not correct. Still, why worry? Use LocalThread, clone the NumberFormat, or just make a new one. Efficiency in terms of object creation is not a real concern most of the time (but not always).
编辑正如 Michael Borgwardt 指出的那样,我对成员变量的预感是不正确的。不过,为什么要担心?使用 LocalThread,克隆 NumberFormat,或者只是创建一个新的。大多数时候(但并非总是如此),对象创建方面的效率并不是真正的问题。

