简体   繁体   中英

Java: Synchronization issue with NumberFormat?

I use java.text.NumberFormat simply to convert numbers into more readable Strings, with commas separating thousands, etc. Basically I define it as:

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."

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?

Thanks!

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.

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.

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.

Looking at the source code of NumberFormat and DecimalFormat , there don't seem to be any fields used for intermediate results - the only problem is that the format itself (eg 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.

If you never use the setters, then it should be 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 ThreadLocal sounds like a good compromise.

NumberFormat is an abstract class . Its default when calling getInstance is to return an instance of DecimalFormat . DecimalFormat uses a bunch of fields for maintaining its position within its formatting process, patterns for prefixes and suffixes, boolean s indicating whether or not to use exponential notation and thousands grouping, int s to describe the size of its integer and fraction parts, etc.

The ThreadLocal option is a great way to go if you expect any concurrent formatting. Note that all subclasses of the abstract Format class are considered not thread-safe, so formatting dates should be handled with this much care as well.

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.

Edit As 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) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM