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

Вызов метода статического java.text.DateFormat не рекомендуется?

Я получаю ошибку "Найти ошибки" - вызов метода статического 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);
4b9b3361

Ответ 1

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 и Sun Bug # 6178997.

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

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

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

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

Ответ 2

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);

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

  • Создание экземпляра каждый раз
  • Синхронизирующий доступ
  • Использование 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 )

Ответ 6

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

Ответ 7

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

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

Ответ 8

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