Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is TimeZone.getTimeZone(id) synchronized, and why this isn't documented?

Tags:

java

java.util.TimeZone.getTimeZone(id) is a method to obtain a timezone based on an id. While I was using the class I opened it with a decompiler and noticed that it is synchronized. And since it is static, this means that no two threads can invoke the method at the same time. This could be very painful if multiple threads (in a web application for example) are often getting timezones. Why does it have to be synchronized?

Then I realized that the documentation doesn't say anything about synchronization. So, my decompiler could be wrong. Then I opened the source, and it is synchronized. Why this is not documented? I'm aware that javadoc doesn't include the synchronized keyword, but it could have been mentioned.

The solution, of course, is to use joda-time DateTimeZone

like image 511
Bozho Avatar asked Apr 15 '11 20:04

Bozho


People also ask

What is TimeZone getDefault?

TimeZone represents a time zone offset, and also figures out daylight savings. Typically, you get a TimeZone using getDefault which creates a TimeZone based on the time zone where the program is running. For example, for a program running in Japan, getDefault creates a TimeZone object based on Japanese Standard Time.

What is default TimeZone in Java?

According to javadoc the java. util. Date class represents number of milliseconds since the standard base time known as "the epoch", namely 1 January 1970, 00:00:00 GMT.

How do I change the TimeZone in Java?

You can make use of the following DateFormat. SimpleDateFormat myDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); myDate. setTimeZone(TimeZone. getTimeZone("UTC")); Date newDate = myDate.

What is raw offset?

The getRawOffset() method of TimeZone class returns the time in milliseconds for the given TimeZone. The values are affected by the daylight saving time that is why it is called the raw offset.


2 Answers

The method can end up actually creating a TimeZone (follow the code down) and adding it to a Map. I'm guessing that everyone considered that this isn't a method you should be calling often and took the easy way out.

I'd have difficulty coming up with a legitimate case where this synchronized would be contended. Uncontended synchronized (even in really high-performance cases, which is something I work on quite often) is cheap as chips.

To get contention, you need not just many threads, but many threads that are hitting this particular block of code at the same time. If you were really having a problem with that in this case, you could easily keep your own cache in a ConcurrentHashMap, or in an entirely unlocked structure.

As to why it's not documented - synchronization is a property of the implementation. You'd be welcome to implement an alternative library that doesn't do this synchronization. The JDK docs are documenting the Java libraries, not (for the most part) Sunacle's implementation thereof.

like image 134
Jon Bright Avatar answered Sep 22 '22 13:09

Jon Bright


We saw this same issue, blocking threads in TimeZone. It looks like a regression introduced in Nov 2011, see http://hg.openjdk.java.net/jdk6/jdk6/jdk/annotate/dd8956e41b89/src/share/classes/java/util/TimeZone.java. Previously TimeZone used InheritableThreadLocal for the Map. TimeZone functions are now controlled by SecurityManager (with a synchronized HashMap under the AppContext class). The following functions are affected: Date.normalize (called by toString, getTime, and a bunch of deprecated methods), Calendar.getInstance (except for the one where Locale is a parameter). http://coffeedriven.org/2012/10/14/be-carefull-with-calendar-getinstance-and-timezone-gettimezone also refers to the same issue.

The stack trace (JDK6.45) from VisualVM:

java.lang.Thread.State: BLOCKED (on object monitor)
at sun.awt.AppContext.get(AppContext.java:572)
- waiting to lock <0x0000000705490070> (a java.util.HashMap)
at sun.awt.AppContext$6.get(AppContext.java:774)
at java.util.TimeZone.getDefaultInAppContext(TimeZone.java:637)
at java.util.TimeZone.getDefaultRef(TimeZone.java:523)
at java.util.Date.normalize(Date.java:1176)
at java.util.Date.toString(Date.java:1010)

I intend to file a bug report with Oracle on this, I just need to recreate a small test case to clearly demonstrate the problem, with a suggested code fix.

The JodaTime documentation states: Joda-Time also allocates very few temporary objects during operations, and performs almost no thread synchronization. In systems that are heavily multi-threaded or use a lot of memory, Calendar, SimpleDateFormat, and TimeZone can become bottlenecks. When the Joda-Time classes are used instead, the bottlenecks go away.

The workaround is to either use JodaTime library, or to patch the JDK TimeZone class, or wait for Oracle to remediate the issue.

like image 36
Bob Fields Avatar answered Sep 19 '22 13:09

Bob Fields