java.util.TimeZone.getTimeZone(id)是一种基于id获取时区的方法.当我使用这个类时,我用反编译器打开它,发现它是synchronized.既然如此static,这意味着没有两个线程可以同时调用该方法.如果多个线程(例如在Web应用程序中)经常获得时区,这可能会非常痛苦.为什么必须同步?
然后我意识到文档没有说同步.所以,我的反编译器可能是错误的.然后我打开了源,它是同步的.为什么没有记录?我知道javadoc不包含synchronized关键字,但可以提到它.
当然,解决方案是使用joda-time DateTimeZone
该方法最终可以实际创建一个TimeZone(遵循代码)并将其添加到Map.我猜大家都认为这不是你应该经常打电话的方法,而是采取了简单的方法.
我很难想出一个synchronized可以争辩的合法案例.无争议synchronized(即使在非常高性能的情况下,这是我经常工作的东西)作为芯片便宜.
要获得争用,您不仅需要许多线程,还需要同时触及此特定代码块的许多线程 .如果在这种情况下你确实遇到了问题,你可以轻松地将自己的缓存保存在一个ConcurrentHashMap或完全解锁的结构中.
至于为什么没有记录 - 同步是实现的属性.欢迎您实现不执行此同步的备用库.JDK文档记录了Java库,而不是(大部分)Sunacle的实现.
小智 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)
Run Code Online (Sandbox Code Playgroud)
我打算在此向Oracle提交错误报告,我只需要重新创建一个小的测试用例,以便通过建议的代码修复来清楚地演示问题.
JodaTime文档声明:Joda-Time在操作期间也分配了很少的临时对象,并且几乎不执行任何线程同步.在大量多线程或使用大量内存的系统中,Calendar,SimpleDateFormat和TimeZone可能成为瓶颈.当使用Joda-Time类时,瓶颈就会消失.
解决方法是使用JodaTime库,或修补JDK TimeZone类,或等待Oracle修复问题.
| 归档时间: |
|
| 查看次数: |
3155 次 |
| 最近记录: |