Предупреждение FindBugs при инициализации ThreadLocal

У меня есть экземпляр ThreadLocal, который был инициализирован переопределенным методом initValue. Также я аннотировал его @edu.umd.cs.findbugs.annotations.SuppressWarnings("SIC_INNER_SHOULD_BE_STATIC_ANON") следующим образом.

@edu.umd.cs.findbugs.annotations.SuppressWarnings("SIC_INNER_SHOULD_BE_STATIC_ANON")
private ThreadLocal<Integer> dbSwitchCount=new ThreadLocal<Integer>() {
    @Override 
    protected Integer initialValue() {
        return 0;
    }
};

Тем не менее отчет Sonar жалуется на «Производительность - может быть преобразована в именованный статический внутренний класс». Как я могу убедиться, что вышеуказанная жалоба игнорируется, или как лучше всего избежать этой жалобы.


person Brinal    schedule 04.09.2015    source источник
comment
Какую версию Java вы используете? Если вы используете Java 8, я бы просто использовал new ThreadLocal<Integer>().withInitial(() -> 0);   -  person Jon Skeet    schedule 04.09.2015
comment
К сожалению, я застрял в Java 6   -  person Brinal    schedule 04.09.2015


Ответы (2)


Делайте то, что предлагает Sonar: «Можно преобразовать в именованный статический внутренний класс».

Именованный статический внутренний класс:

class MyClass {
    static class MyThreadLocal extends ThreadLocal<Integer> {
        @Override 
        protected Integer initialValue() {
            return 0;
        }
    }
    private ThreadLocal<Integer> dbSwitchCount = new MyThreadLocal();
}

Я думаю, что причина, по которой Sonar считает, что это улучшение «Производительности», заключается в том, что анонимный класс нестатичен, и его статика улучшает управление памятью.

person Andreas    schedule 04.09.2015
comment
Это должно работать. Но мне интересно, почему не применяются SuppressWarnings? - person Brinal; 04.09.2015

Аннотация не работает, потому что вы аннотируете поле dbSwitchCount, а не анонимный класс, и отчет об ошибке не привязан к полю. Вот как отчет об ошибке выглядит в формате XML:

<BugInstance type="SIC_INNER_SHOULD_BE_STATIC_ANON" priority="3" rank="20" abbrev="SIC" 
             category="PERFORMANCE" first="1">
  <Class classname="MyClass$1">
    <SourceLine classname="MyClass$1" start="1" end="10" 
                sourcefile="MyClass.java" sourcepath="MyClass.java"/>
  </Class>
  <SourceLine classname="MyClass$1" start="7" end="7" startBytecode="0" endBytecode="0" 
              sourcefile="MyClass.java" sourcepath="MyClass.java"/>
</BugInstance>

Видите, ничего о поле dbSwitchCount. Таким образом, когда фильтр подавления работает, он не знает, что аннотация dbSwitchCount как-то связана с этим отчетом об ошибке. И, к сожалению, я не вижу возможности аннотировать сам анонимный класс. Единственное, что вы можете сделать, чтобы подавить это предупреждение без изменения фактического кода, — вместо этого аннотировать внешний класс:

@SuppressFBWarnings("SIC_INNER_SHOULD_BE_STATIC_ANON")
public class MyClass {

    private final ThreadLocal<Integer> dbSwitchCount=new ThreadLocal<Integer>() {
        @Override 
        protected Integer initialValue() {
            return 0;
        }
    };
}

Таким образом, предупреждение исчезает (кстати, вместо этого рекомендуется использовать аннотацию @SuppressFBWarnings).

В общем, привязанные к экземпляру (нестатические) локальные потоки подозрительны. См., например, этот вопрос. Таким образом, вероятно, исходная проблема заключается в том, что dbSwitchCount должен быть объявлен как статический (таким образом предупреждение SIC_INNER_SHOULD_BE_STATIC_ANON также исчезнет).

ОБНОВЛЕНИЕ Я проверил код FindBugs для этого детектора. Похоже, можно добавить отсутствующую аннотацию ошибки, чтобы можно было подавить предупреждение, аннотирующее поле или заключающий метод. Я создал тикет в нашем баг-трекере.

ОБНОВЛЕНИЕ 2 Исправлено в стволе FindBugs.

person Tagir Valeev    schedule 07.09.2015