Вызов метода static java.text.DateFormat не рекомендуется? - PullRequest
41 голосов
/ 09 марта 2010

Я получаю Ошибка поиска Ошибка - вызов метода static java.text.DateFormat и Я не знаю причину, почему нехорошо / желательно делать эти вещи ниже.

private static final Date TODAY = Calendar.getInstance().getTime();
private static final DateFormat yymmdd = new SimpleDateFormat("yyMMdd"); 

private String fileName = "file_" + yymmdd.format(TODAY);

Ответы [ 8 ]

80 голосов
/ 09 марта 2010

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

Мое предложение состояло бы в том, чтобы сделать ваши переменные локальными там, где вы их используете, вместо того, чтобы делать их статическими свойствами класса. Похоже, что вы можете делать это при инициализации класса, поэтому вы можете сделать это в конструкторе:

public class MyClass {
    private String fileName;

    public MyClass() {
        final Date today = Calendar.getInstance().getTime();
        final DateFormat yymmdd = new SimpleDateFormat("yyMMdd"); 

        this.fileName = "file_" + yymmdd.format(TODAY);
    }
    ...
}

И если вам нужно использовать форматтер в нескольких местах, вы можете просто сделать шаблон static final и создать новый локальный DateFormat, когда это необходимо:

public class MyClass {
    private static final String FILENAME_DATE_PATTERN = "yyMMdd";

    public void myMethod() {
        final DateFormat format = new SimpleDateFormat(FILENAME_DATE_PATTERN);
        // do some formatting
    }
}

Документация FindBugs для этой проблемы гласит:

Как утверждает JavaDoc, DateFormats небезопасно для многопоточных использовать. Детектор обнаружил звонок экземпляр DateFormat, который имеет были получены через статическое поле. это выглядит подозрительно.

Для получения дополнительной информации см. Sun Ошибка # 6231579 и ошибка солнца # 6178997.

И Javadoc для DateFormat предлагает:

Форматы даты не синхронизированы. Это рекомендуется создать отдельный форматировать экземпляры для каждого потока. Если несколько потоков обращаются к формату одновременно он должен быть синхронизирован внешне.

Ответ Джека Лиу также имеет хорошее замечание о семантике вашего статического использования "СЕГОДНЯ".

Кроме того, я действительно видел, как это происходит в производственной среде с большим трафиком, и отладка вначале очень запутанная вещь; поэтому, по моему опыту, предупреждение FindBugs на самом деле является полезным предложением (в отличие от некоторых других правил статического анализа, которые иногда кажутся придирчивыми).

15 голосов
/ 09 марта 2010

Commons Lang имеет FastDateFormat объект, который является потокобезопасным. Это только форматирование, но не анализирует.

Если вы можете использовать commons-lang, это может хорошо сработать для вас.

private static final Date TODAY = Calendar.getInstance().getTime();
private static final FastDateFormat yymmdd = FastDateFormat.getInstance("yyMMdd");

private String fileName = "file_" + yymmdd.format(TODAY);
4 голосов
/ 02 ноября 2015

Альтернативой, которая не была упомянута, является использование ThreadLocal. См. http://www.javacodegeeks.com/2010/07/java-best-practices-dateformat-in.html для получения дополнительной информации + сравнение производительности между 3 параметрами:

  • Создание экземпляра каждый раз
  • Синхронизация доступа
  • Использование ThreadLocal

Пример использования ThreadLocal:

private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyMMdd");
    }
};

Использование:

DATE_FORMAT.get().format( TODAY )
4 голосов
/ 09 марта 2010

Я не уверен, что FindBugs жалуется на это, но одна проблема, которую я вижу с вашим кодом, состоит в том, что вы определяете TODAY как переменную уровня класса (статическая), постоянная (финальная). Это говорит о том, что вы хотите, чтобы TODAY никогда не менялся (я не верю, что это так, поскольку java.util.Dates изменчивы, но это другая история).

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

Это может быть совсем не ошибка в вашем коде, но цель не ясна, и я считаю, что может быть тем, на что жалуется FindBugs.

4 голосов
/ 09 марта 2010

Вы уверены, что это не

private static final DateFormat yymmdd = new SimpleDateFormat("yyMMdd"); 

? Вот что указывает сообщение об ошибке.

Я думаю, что он нацелен на то, что DateFormat не является потокобезопасным, поэтому наличие экземпляра в качестве статического поля указывает на потенциальные условия гонки.

0 голосов
/ 09 марта 2010

Вы можете избавиться от этого, обернув все ссылки на DateFormat в блок синхронизации - просто убедитесь, что все вызовы заключены в тот же объект синхронизации!

0 голосов
/ 09 марта 2010

Я полагаю, это потому, что формат не является потокобезопасным?

(Я не видел, на что жалуются findbugs, можете ли вы предоставить текст предупреждения?)

0 голосов
/ 09 марта 2010

Это не потокобезопасно, с одной стороны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...