Подтвердить что ты не робот

Почему синхронизация TimeZone.getTimeZone(id) и почему это не документировано?

java.util.TimeZone.getTimeZone(id) - это метод получения часового пояса на основе идентификатора. Пока я использовал класс, я открыл его декомпилятором и заметил, что он synchronized. И поскольку это static, это означает, что ни один из двух потоков не может вызвать метод одновременно. Это может быть очень болезненным, если несколько потоков (например, в веб-приложении) часто получают временные интервалы. Почему он должен быть синхронизирован?

Тогда я понял, что в документации ничего не говорится о синхронизации. Итак, мой декомпилятор может быть неправильным. Затем я открыл источник и синхронизирован. Почему это не документировано? Я знаю, что javadoc не включает ключевое слово synchronized, но его можно было бы упомянуть.

Решение, конечно же, должно использовать joda-time DateTimeZone

4b9b3361

Ответ 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 исправит проблему.