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

Для объектно-ориентированного API matplotlib можно построить собственный текст на x-ticks файла axis со следующим кодом:

x = np.arange(2,10,2)
y = x.copy()
x_ticks_labels = ['jan','feb','mar','apr','may']

fig, ax = plt.subplots(1,1) 
ax.plot(x,y)

# Set number of ticks for x-axis
ax.set_xticks(x)
# Set ticks labels for x-axis
ax.set_xticklabels(x_ticks_labels, rotation='vertical', fontsize=18)

42
задан setzamora 9 March 2010 в 14:30
поделиться

7 ответов

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

И если вам нужно использовать средство форматирования в нескольких местах, вы можете просто сделать шаблон статическим. 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 являются {{1} } по своей сути небезопасно для многопоточного использования . Детектор обнаружил вызов экземпляра DateFormat, который был получен через статическое поле. Это выглядит подозрительно.

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

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

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

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

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

82
ответ дан 26 November 2019 в 22:38
поделиться

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

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

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

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

4
ответ дан 26 November 2019 в 22:38
поделиться

Во-первых, он не является потокобезопасным.

0
ответ дан 26 November 2019 в 22:38
поделиться

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

(Я не видел, на что жалуются ошибки findbug, можете ли вы предоставить {{1 }} текст предупреждения?)

0
ответ дан 26 November 2019 в 22:38
поделиться

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);
15
ответ дан 26 November 2019 в 22:38
поделиться

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

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

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

4
ответ дан 26 November 2019 в 22:38
поделиться

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

0
ответ дан 26 November 2019 в 22:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: