2014-09-30 2 views
0

У меня есть код, из которого я пытаюсь получить экземпляр своего класса, поскольку я написал обертку около java.util.logging.Logger.Неатомическое использование ошибки проверки/помехи во время статического анализа

Ниже фрагмент кода в моем ClientLogger классе -

private static final Map<Class<?>, ClientLogger> s_classLoggers = new ConcurrentHashMap<Class<?>, ClientLogger>(); 

final private Logger m_logger; 

private ClientLogger(final Class<?> caller) { 
    m_logger = Logger.getInstance(caller); 
} 

public static ClientLogger getInstance(final Class<?> klass) { 
    final ClientLogger result; 

    if (s_classLoggers.containsKey(klass)) { 
     result = s_classLoggers.get(klass); 
    } else { 
     result = new ClientLogger(klass); 
     s_classLoggers.put(klass, result); 
    } 

    return result; 
} 

И это так, как я его инициализации в моих классах, где я должен использовать мой выше регистратор -

private static final ClientLogger s_logger = ClientLogger.getInstance(TestLogger.class); 

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

Non-atomic use of check/put on this line s_classLoggers.put(klass, result); 

в моем классе ClientLogger, и я не уверен, почему? Что-то не так я здесь делаю?

UPDATE: -

Вот мой обновленный код -

private static final ConcurrentHashMap<Class<?>, ClientLogger> s_classLoggers = new ConcurrentHashMap<Class<?>, ClientLogger>(); 

public static ClientLogger getInstance(final Class<?> klass) { 
    final ClientLogger result; 

    result = new ClientLogger(klass); 
    s_classLoggers.putIfAbsent(klass, result); 

    return result; 
} 

Другой Update: -

private static final ConcurrentHashMap<Class<?>, ClientLogger> s_classLoggers = new ConcurrentHashMap<Class<?>, ClientLogger>(); 

public static ClientLogger getInstance(final Class<?> klass) { 
    ClientLogger result; 

    result = s_classLoggers.putIfAbsent(klass, new ClientLogger(klass)); 
    if (result == null) { 
     result = new ClientLogger(klass); 
    }  

    return result; 
} 

ответ

2

Ваш код не поточно-, потому что другой поток может вызвать put() между двумя вашими вызовами в первом потоке.

Вместо этого вы должны позвонить по номеру putIfAbsent().

+0

С java 8 или изменить объявленный тип поля на 'ConcurrentHashMap'. –

+0

Я не вижу 'putIfAbsent()' для 's_classLoggers' карты. Не знаете почему? И я использую 'java.util.concurrent.ConcurrentHashMap' – john

+0

@ user2809564: вам нужно изменить тип поля на' ConcurrentHashMap '. – SLaks

1

тестируется

s_classLoggers.containsKey(klass) 

на одной строке кода. Несколько строк позже вы кладете в значении

s_classLoggers.put(klass, result); 

Конечно, другой поток может быть обновляемым хэш-карту в то же время. В многопоточности вы не можете тестировать на одной строке, а затем условно работать с другой строкой, потому что условие может быть ложным. Точно так же строка get позже может вернуть значение null, потому что другой поток мог удалить запись, в которой была строка раньше.

Атомный операция, где тест и обновление выполняется в одной операции:

newLogger = new ClientLogger(klass); 
result = s_classLoggers.putIfAbsent(klass, newLogger); 
if (result == null) { 
    result = newLogger; 
} 

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

+0

Я не вижу 'putIfAbsent()' для 's_classLoggers' карты. Не знаете почему? И я использую 'java.util.concurrent.ConcurrentHashMap' – john

+0

здесь ссылка на doc: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html#putIfAbsent % 28K,% 20V% 29 – AgilePro

+0

'result = s_classLoggers.putIfAbsent (klass, new ClientLogger (klass));' Это вернет null для первого вызова. Правильно? И тогда исключение NPE будет выбрано в моем коде. – john

Смежные вопросы