Путаница с безопасностью потоков - пример SimpleDateFormat - PullRequest
10 голосов
/ 13 апреля 2011

У меня есть вопрос о безопасности потоков.Из того, что мне сказали, SimpleDateFormat не является потокобезопасным.Мне было интересно, какие эффекты это произвело бы, если бы я использовал его следующим образом в моем контроллере пружины:

private final static SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd yyyy", Locale.US);

Позже в моей функции контроллера я использую его следующим образом:

  try {
        changedate = changedate.substring(0, 15);                                                
        calcDate = dateFormat.parse(changedate);
    } catch (ParseException e2) {
        logger.error("Date Parsing Problem", e2); 
    }

calcDate затем добавляется к моему объекту модели и возвращается ModelAndView.

Итак, какие проблемы я увижу, используя его таким образом?Устранит ли просто удаление статического ключевого слова какие-либо проблемы, потому что тогда каждый поток будет использовать свой собственный экземпляр dateFormat?Любая ясность в этом предмете в отношении безопасности потоков была бы очень признательна.

Спасибо

Ответы [ 7 ]

21 голосов
/ 13 апреля 2011

SimpleDateFormat.parse() использует переменную экземпляра с именем calendar для построения даты из строки.Если два потока попытаются выполнить синтаксический анализ одновременно, переменная calendar будет перекрыта, и вы получите неправильные результаты.

Если переменная не является статической, это не обязательно поможет, так как два потока все еще могутиспользуя тот же контроллер.Лучшее решение - либо создавать новый объект DateFormat каждый раз, когда вы анализируете дату, либо использовать локальное хранилище потока.Более того, используйте JodaTime , который имеет парсобезопасные парсеры.

5 голосов
/ 13 апреля 2011

Так, какие проблемы я увижу, используя его таким образом?

Разработчики SimpleDateFormat приняли очень странное решение - при работе parse() они хранят частично разобранную дату в поле SimpleDateFormat. Очевидно, это означает, что вы не можете вызывать parse() из нескольких потоков одновременно.

Устранит ли просто удаление статического ключевого слова какие-либо проблемы, потому что тогда каждый поток будет использовать свой собственный экземпляр dateFormat?

Удаление static вам не поможет, поскольку контроллеры Spring по умолчанию имеют одноэлементную область, поэтому Spring использует один экземпляр вашего контроллера для обслуживания всех запросов.

2 голосов
/ 13 апреля 2011

SimpleDateFormat имеет состояние всего экземпляра при разборе и, следовательно, не является потокобезопасным. Если вы используете его из нескольких потоков, это приведет к сбою (например, сбои java :-), без сбоев процессов и т. П.). Удаление статического ключевого слова не обязательно решает проблему, потому что это зависит от экземпляра и все еще может использоваться из нескольких потоков.

Вы можете создать локальный экземпляр в методе, описанном выше, чтобы каждый разбор выполнялся с использованием собственного средства форматирования или воспроизведения с локальными переменными потока.

2 голосов
/ 13 апреля 2011

Лично я бы избежал всех этих проблем, просто используя JodaTime. API намного богаче, у него нет проблем с многопоточностью и он намного быстрее.

2 голосов
/ 13 апреля 2011

Не уверен, какие проблемы вы бы увидели, если бы сделали это таким образом.Но Javadocs предупреждают о параллельном доступе к SimpleDateFormat и о том, как его использование определенно предполагает одновременный доступ.Удаление статического кода не устранит проблему параллелизма, если вы не реализуете какой-либо тип политики синхронизации для включающего класса или иным образом не препятствует доступу к нему нескольких потоков.

Вы можете попытаться создать SimpleDateFormat для каждого потока, создав его экземпляр в теле метода и убедившись, что ссылка на SimpleDateFormat никогда не «ускользает» от метода.Другими словами, объявите переменную, создайте экземпляр объекта и используйте объект в том же методе.Это обеспечит удаление ссылки для этого SimpleDateFormat при выходе из метода.

0 голосов
/ 04 января 2016

Другой способ, если вы можете убедиться, что каждый раз, когда ваш контроллер вызывается, вы возвращаете новый экземпляр, а затем удаляете статическую ссылку.

0 голосов
/ 28 февраля 2013

Разработчики Android могут использовать безопасные (локализованные потоки) оболочки вокруг SimpleDateFormat, которые находятся в: org.apache.http.impl.cookie.DateUtils

Исходный код для реализацииздесь (например, FROYO API Level 8):

...