![](/img/trans.png)
[英]Why is the TimeZone.getTimeZone(“MST”) method is different from getTimeZone(“US/Mountain”)?
[英]Why is TimeZone.getTimeZone(id) synchronized, and why this isn't documented?
java.util.TimeZone.getTimeZone(id)
是一种基于id获取时区的方法。 当我使用该类时,我用反编译器打开它,发现它是synchronized
。 由于它是static
,这意味着没有两个线程可以同时调用该方法。 如果多个线程(例如在Web应用程序中)经常获得时区,这可能会非常痛苦。 为什么必须同步?
然后我意识到文档没有说同步。 所以,我的反编译器可能是错误的。 然后我打开了源 ,它是同步的。 为什么没有记录? 我知道javadoc不包含synchronized
关键字,但可以提到它。
当然,解决方案是使用joda-time DateTimeZone
该方法最终可以实际创建TimeZone
(遵循代码)并将其添加到Map
。 我猜大家都认为这不是你应该经常打电话的方法,而是采取了简单的方法。
我很难想出一个合法的案例,其中这个synchronized
会被争议。 无争议的synchronized
(即使在非常高性能的情况下,这是我经常工作的东西)作为芯片便宜。
要获得争用,您不仅需要许多线程,还需要同时触及此特定代码块的许多线程。 如果您在这种情况下遇到问题,可以轻松地将自己的缓存保存在ConcurrentHashMap
,或者保存在完全解锁的结构中。
至于为什么没有记录 - 同步是实现的属性。 欢迎您实现不执行此同步的备用库。 JDK文档记录了Java库,而不是(大部分)Sunacle的实现。
我们看到了同样的问题,在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修复问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.