22

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!

5 Answers 5

23

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Measured this using gist.github.com/jontejj/5430320, the results are published at 1.microbenchmarks.appspot.com/run/[email protected]/… the gain is actually quite substantial if formatting numbers are the only thing going on. This even though NumberFormat keeps a cache for created formatters and only clones them before returning them.
And the same applies to all subclasses.. Especially DateFormat
The way I understand Open / Closed principle means that you should not extend a class that is not thread safe and make it thread safe in the subclass. Create something else from scratch instead, maybe use NumberFormat internally but do not extend it.
15

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.

Comments

4

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

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.

2 Comments

I know this is an old answer, but... You really shouldn't go by the source code. Even if you know what version of Java you're using, it's different between vendors. (I've seen lots of differences between the IBM and Sun/Oracle JVMs, for example.)
In my version of the JDK there actually is intermediate results stored, but as you said YMMV.
2

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, booleans indicating whether or not to use exponential notation and thousands grouping, ints 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.

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.