I have a code from which I am trying to get the instance of my class as I have written a wrapper around java.util.logging.Logger
.
Below is the snippet of code in my ClientLogger
class -
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;
}
And this is the way I am initializing it in my other classes where I need to use my above logger -
private static final ClientLogger s_logger = ClientLogger.getInstance(TestLogger.class);
Now when I am running my static analysis tool, it is complaining as in my ClientLogger
class -
Non-atomic use of check/put on this line s_classLoggers.put(klass, result);
So I modified my above code like this to make it thread safe -
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));
// is below line thread safe and efficient?
if (result == null) {
result = new ClientLogger(klass);
}
return result;
}
Below is the way I will be initializing it to get my logger instance -
private static final ClientLogger s_logger = ClientLogger.getInstance(TestLogger.class);
So is my above code thread safe? I am doing result == null
check since for the first time, it won't be there in the map so I need to make a new value of it and because of that, I need to remove the final modifier of result.