为什么TimeZone.getTimeZone(id)已同步,为什么没有记录?

时间:2011-04-15 20:50:35

标签: java

java.util.TimeZone.getTimeZone(id)是一种基于id获取时区的方法。当我使用该类时,我用反编译器打开它,发现它是synchronized。由于它是static,这意味着没有两个线程可以同时调用该方法。如果多个线程(例如在Web应用程序中)经常获得时区,这可能会非常痛苦。为什么必须同步?

然后我意识到文档没有说同步。所以,我的反编译器可能是错误的。然后我打开了the source,它被同步了。为什么没有记录?我知道javadoc不包含synchronized关键字,但可以提及它。

当然,解决方案是使用joda-time DateTimeZone

2 个答案:

答案 0 :(得分:7)

该方法最终可以实际创建TimeZone(遵循代码)并将其添加到Map。我猜大家都认为这不是一个你应该经常打电话的方法,并且很容易解决。

我很难想出一个合法的案例,其中synchronized会被争议。无争议的synchronized(即使在非常高性能的情况下,这是我经常使用的东西)也很便宜。

要获得争用,您不仅需要多个线程,还需要同时触及此特定代码块的许多线程。如果您在这种情况下遇到问题,可以轻松地将自己的缓存保存在ConcurrentHashMap或完全解锁的结构中。

至于为什么没有记录 - 同步是实现的属性。欢迎您实现不执行此同步的备用库。 JDK文档记录了Java库,而不是(大部分)Sunacle的实现。

答案 1 :(得分:6)

我们看到了同样的问题,阻塞了TimeZone中的线程。它看起来像2011年11月引入的回归,见http://hg.openjdk.java.net/jdk6/jdk6/jdk/annotate/dd8956e41b89/src/share/classes/java/util/TimeZone.java。以前TimeZone使用了InheritableThreadLocal作为Map。 TimeZone函数现在由SecurityManager控制(在AppContext类下具有同步的HashMap)。以下函数受到影响:Date.normalize(由toString,getTime和一堆不推荐的方法调用),Calendar.getInstance(Locale是参数的那个除外)。 http://coffeedriven.org/2012/10/14/be-carefull-with-calendar-getinstance-and-timezone-gettimezone也指同一问题。

VisualVM的堆栈跟踪(JDK6.45):

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)

我打算在此向Oracle提交错误报告,我只需要重新创建一个小测试用例,以便通过建议的代码修复来清楚地演示问题。

JodaTime文档说明: Joda-Time在操作期间也分配了很少的临时对象,并且几乎不执行任何线程同步。在大量多线程或使用大量内存的系统中,Calendar,SimpleDateFormat和TimeZone可能成为瓶颈。当使用Joda-Time类时,瓶颈就会消失。

解决方法是使用JodaTime库,或修补JDK TimeZone类,或等待Oracle修复问题。

相关问题