Почему синхронизация TimeZone.getTimeZone(id) и почему это не документировано?
java.util.TimeZone.getTimeZone(id)
- это метод получения часового пояса на основе идентификатора. Пока я использовал класс, я открыл его декомпилятором и заметил, что он synchronized
. И поскольку это static
, это означает, что ни один из двух потоков не может вызвать метод одновременно. Это может быть очень болезненным, если несколько потоков (например, в веб-приложении) часто получают временные интервалы. Почему он должен быть синхронизирован?
Тогда я понял, что в документации ничего не говорится о синхронизации. Итак, мой декомпилятор может быть неправильным. Затем я открыл источник и синхронизирован. Почему это не документировано? Я знаю, что javadoc не включает ключевое слово synchronized
, но его можно было бы упомянуть.
Решение, конечно же, должно использовать joda-time DateTimeZone
Ответы
Ответ 1
Метод может фактически создать TimeZone
(выполнить код вниз) и добавить его в Map
. Я предполагаю, что все считают, что это не метод, который вы должны часто звонить, и выбрали простой способ.
Мне было бы сложно придумать законный случай, когда этот synchronized
будет обсуждаться. Беспокойный synchronized
(даже в действительно высокопроизводительных случаях, в котором я часто работаю) дешево, как чипы.
Чтобы получить конкуренцию, вам нужно не просто много потоков, но много потоков, которые одновременно попадают в этот конкретный блок кода. Если у вас действительно возникла проблема с этим в этом случае, вы можете легко сохранить свой собственный кеш в ConcurrentHashMap
или в полностью разблокированной структуре.
Что касается того, почему он не документирован - синхронизация является свойством реализации. Вы можете использовать альтернативную библиотеку, которая не выполняет эту синхронизацию. Документы JDK документируют библиотеки Java, а не (по большей части) реализацию Sunacle.
Ответ 2
Мы видели эту же проблему, блокируя потоки в TimeZone. Это похоже на регресс, введенный в ноябре 2011 года, см. http://hg.openjdk.java.net/jdk6/jdk6/jdk/annotate/dd8956e41b89/src/share/classes/java/util/TimeZone.java. Ранее TimeZone использовал InheritableThreadLocal для Карты. Функции TimeZone теперь контролируются SecurityManager (с синхронизированным HashMap в классе AppContext). Наследуются следующие функции: Date.normalize(вызываемые toString, getTime и куча устаревших методов), Calendar.getInstance(кроме тех, где Locale является параметром). http://coffeedriven.org/2012/10/14/be-carefull-with-calendar-getinstance-and-timezone-gettimezone также относится к той же проблеме.
Трассировка стека (JDK6.45) из 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)
Я намерен записать отчет об ошибках в Oracle, мне просто нужно воссоздать небольшой тестовый пример, чтобы четко продемонстрировать проблему с предлагаемым исправлением кода.
Документация JodaTime гласит:
Joda-Time также выделяет очень мало временных объектов во время операций и практически не выполняет синхронизацию потоков. В системах, которые сильно многопоточны или используют много памяти, Calendar, SimpleDateFormat и TimeZone могут стать узкими местами. Когда вместо этого используются классы Joda-Time, узкие места уходят.
Обходной путь - либо использовать библиотеку JodaTime, либо исправить класс JDK TimeZone, либо дождаться, когда Oracle исправит проблему.