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 -
Non-atomic use of check/putĀ on this line s_classLoggers.put(klass, result);
in my ClientLogger class and I am not sure why? Is there anything wrong I am doing here?
UPDATE:-
Here is my updated code -
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;
}
Another 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;
}
Your code is not thread-safe, because a different thread might call put() between your two calls on the first thread.
Instead, you should call putIfAbsent().
you are testing
s_classLoggers.containsKey(klass)
on one line of the code. Several lines later you put in a value
s_classLoggers.put(klass, result);
Of course, another thread might have updated the hash map in the mean time. In multithreading, you can not test on one line, and then conditionally operate on another line, because the condition might be false. In the same way, the get a line later might return null because another thread might have removed the entry that was there a line before.
An atomic operation, where the test and update is done in a single operation:
newLogger = new ClientLogger(klass);
result = s_classLoggers.putIfAbsent(klass, newLogger);
if (result == null) {
result = newLogger;
}
(changed the code above so that result is always whatever value that is mapped because putIfAbsent returns null if nothing was mapped before, and in that case the newLogger is put into the map.)
Related
I'm looking for code equivalent to the following:
ConcurrentHashMap<int, Object> map = new ConcurrentHashMap<>();
map.computeIfAbsent(key, n -> f(n));
Where f(n) is HTTP network call and blocking for the result
Bur referring to single element held in AtomicReference<Object> where I need to ensure f is called only once upon even if multiple threads do the access concurrently.
I tried using compareAndSet but this doesn't allow lambda passing.
Does updateAndGet achieve that? Its documentation mentions
The function should be side-effect-free, since it may be re-applied when attempted updates fail due to contention among threads.
Which doesn't seem to fill the need of invoking f only once.
I believe you need something like a concurrent lazy initializer.
It is possible to achieve this using:
If your requirement is to have only 1 instance in an application, you can use a thread-safe singleton. https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
public class Something {
private final Result result;
private Something() {
result = f();
}
private static class LazyHolder {
public static final Something INSTANCE = new Something();
}
public static Something getInstance() {
return LazyHolder.INSTANCE;
}
}
If you want to have it in different places of your application, you can use:
Apache Commons Lang ConcurrentInitializer like LazyInitializer:
ConcurrentInitializer<> lazyInitializer = new LazyInitializer<Result>() {
#Override
protected Foo initialize() throws ConcurrentException {
return f();
}
};
Get instance
Result instance = lazyInitializer.get();
Google's Guava link:
Supplier<Result> resultSupplier = Suppliers.memoize(new Supplier<Result>() {
public Result get() {
return f();
}
});
Yon can create your own concurrent lazy initalizer in lock-free manner.
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
public class LazyConcurrentSupplier<T> implements Supplier<T> {
static class Container<T> {
public static final int NULL_PHASE = -1, CREATING_PHASE = 0, CREATED = 1;
final int i;
final T value;
public Container(int i, T value) {
this.i = i;
this.value = value;
}
}
private final Container<T> NULL = new Container<>(Container.NULL_PHASE, null),
CREATING = new Container<>(Container.CREATING_PHASE, null);
private final AtomicReference<Container<T>> ref = new AtomicReference<>(NULL);
private final Supplier<T> supplier;
public LazyConcurrentSupplier(Supplier<T> supplier) {
this.supplier = supplier;
}
#Override
public T get() {
Container<T> prev;
do {
if (ref.compareAndSet(NULL, CREATING)) {
T res = supplier.get();
ref.set(new Container<>(Container.CREATED, res));
return res;
} else {
prev = ref.get();
if (prev.i == Container.CREATED) {
return prev.value;
}
}
} while (prev.i < Container.CREATED);
return prev.value;
}
}
From your question, I think you want to avoid doing the HTTP request multiple times.
You could have a map of FutureTask(s) that asynchronously performs the HTTP request for you. In this way, if a thread tries to computeIfAbsent it will see the FutureTask created by another thread even if the HTTP operation is not done yet.
You could use an AtomicBoolean with an initial value of true and allow each thread should call AtomicBoolean::getAndSet with the value false. If the return value is true then you execute your function.
This will ensure that the call is only made once since only the first thread will succeed.
I am facing an issue with Guava Caches. When I have only one element in cache, things are fine. But when I load a second element, Its trying to pick with key of earlier entry
private static LoadingCache<String, MyClass> cache = null;
....
public MyClass method(final String id1, final long id2) {
log.error("inside with "+id1);
final String cacheKey = id1+"-"+id2;
if(cache == null){
cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.build(
new CacheLoader<String, MyClass>() {
#Override
public MyClass load(String key) {
return getValue(cacheKey);
}
}
);
}
try {
return cache.get(cacheKey);
} catch (ExecutionException ex) {
log.error("EEE missing entry",ex);
}
}
private MyClass getValue(String cacheKey){
log.error("not from cache "+cacheKey);
...
}
The log says:
inside with 129890038707408035563943963861595603358
not from cache 1663659699-315839912047403113610285801857400882820 // This is key for the earlier entry
For eg, When I call method("1", 2), it loads the value in cache and I am able to get it from cache subsequently. Now I call method ("3", 4), this is not in cache, so getValue() is called and the log prints out the key for method("1", 2)
Where am I going wrong?
Your problem is related to how you create your CacheLoader, if you check well you will see that you initialize it with a given cache key (the value of the local variable cacheKey at the time the cache is lazily initialized) while it should be more generic and rely on the key provided as parameter to the method load of your CacheLoader otherwise it will load the cache by calling getValue(key) with the same key.
It should be this:
new CacheLoader<String, MyClass>() {
#Override
public MyClass load(String key) {
return getValue(key); // instead of return getValue(cacheKey);
}
}
NB: The way you initialize your cache is not thread safe, indeed if it has not been initialized and your method method is called by several threads concurrently it will be created several times instead of one.
One way could be to use the double-checked locking idiom as next:
private static volatile LoadingCache<String, MyClass> cache = null;
public MyClass method(final String id1, final long id2) {
...
if(cache == null){
synchronized (MyClass.class) {
if(cache == null){
cache = ...
}
}
}
NB: Do not initialize a static cache with a CacheLoader based on a non static method, it is much too error prone. Make them both non static or static but don't mix them.
Assuming that you can make both static, your cache initialization will be very simply, it would simply be:
private static final LoadingCache<String, MyClass> cache = CacheBuilder.newBuilder()...
No need to initialize it lazily which will also simplify a lot the code of your method as it will simply be reduce to:
public MyClass method(final String id1, final long id2) {
log.error("inside with "+id1);
final String cacheKey = id1+"-"+id2;
try {
return cache.get(cacheKey);
} catch (ExecutionException ex) {
log.error("EEE missing entry",ex);
}
}
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.
What you need is Java 8's
s_classLoggers.computeIfAbsent(klass, ClientLogger::new);
This will only create the object if it really has to.
Note, the ClientLogger::new is amazing short hand as it is short for k -> new ClientLogger(k) which is short for
new Function<Class<?>, ClientLogger>() {
public ClientLogger apply(Class<?> k) {
return new ClientLogger(k);
}
}
and the lambda doesn't even generate a class at compile time, though the JVM can (and does in Java 8) create a class at runtime.
Otherwise you might find using a write lock is safer.
public static ClientLogger getInstance(final Class<?> klass) {
ClientLogger result = s_classLoggers.get(klass);
if (result != null)
return result; // fast path
// slow, but rare path
synchronized (s_classLoggers) {
result = s_classLoggers.get(klass);
if (result == null)
s_classLoggers.put(klass, result = new ClientLogger(klass));
}
return result;
}
CocncurrentHashMap provides a method to atomically check and add an element if it is not present via putIfAbsent method as shown in the example below
xmlObject = new XMLObejct(xmlId);
mapOfXMLs.putIfAbsent(xmlId, xmlObject);
However my dilemma is that , I have to create that xmlObject in advance. Is there a way to postpone the object creation after the key present check.
I want all three things below to happen atomically
Check if the key present
Create object if key is not present.
Add the object to map.
I know I can achieve this using synchronized block , If I am using a synchronized block , why use a CocurrentHashMap?
The Guava Caches offer such a functionality ( http://code.google.com/p/guava-libraries/wiki/CachesExplained ) though it's somewhat hidden.
If you can already use Java 8, then you can use computeIfAbsent. But I guess if you could use it, you would not have asked....
The standard, almost perfect pattern is this:
Foo foo = map.get(key);
if(foo == null) {
map.putIfAbsent(new Foo());
foo = map.get(key);
}
It does sometimes result in an extra object, but extremely infrequently, so from a performance standpoint is certainly fine. It only wouldn't be fine if constructing your object inserted into a database or charged a user or some such.
I've encountered this scenario a couple of times, and they allowed for the value to be created lazily. It may not apply to your use case, but if it does, this is basically what I did:
static abstract class Lazy<T> {
private volatile T value;
protected abstract T initialValue();
public T get() {
T tmp = value;
if (tmp == null) {
synchronized (this) {
tmp = value;
if (tmp == null)
value = tmp = initialValue();
}
}
return tmp;
}
}
static ConcurrentHashMap<Integer, Lazy<XmlObject>> map = new ConcurrentHashMap<>();
and then populating the map:
final int id = 1;
map.putIfAbsent(id, new Lazy<XmlObject>() {
#Override
protected XmlObject initialValue() {
return new XmlObject(id);
}
});
System.out.println(map.get(id).get());
You can of course create a specialized LazyXmlObject for convenience:
static class LazyXmlObject extends Lazy<XmlObject> {
private final int id;
public LazyXmlObject(int id) {
super();
this.id = id;
}
#Override
protected XmlObject initialValue() {
return new XmlObject(id);
}
}
and the usage would be:
final int id = 1;
map.putIfAbsent(id, new LazyXmlObject(id));
System.out.println(map.get(id).get());
I have several Java enums that looks something like below (edited for confidentiality, etc).
In each case, I have a lookup method that I'm really not satisfied with; in the example below, it is findByChannelCode.
public enum PresentationChannel {
ChannelA("A"),
ChannelB("B"),
ChannelC("C"),
ChannelD("D"),
ChannelE("E");
private String channelCode;
PresentationChannel(String channelCode) {
this.channelCode = channelCode;
}
public String getChannelCode() {
return this.channelCode;
}
public PresentationChannel findByChannelCode(String channelCode) {
if (channelCode != null) {
for (PresentationChannel presentationChannel : PresentationChannel.values()) {
if (channelCode.equals(presentationChannel.getChannelCode())) {
return presentationChannel;
}
}
}
return null;
}
}
The problem is, I feel silly doing these linear lookups when I could just be using a HashMap<String, PresentationChannel>. So I thought of the solution below, but it's a little messier that I would hope and, more to the point, I didn't care to re-invent the wheel when surely someone else has come across this. I wanted to get some of the sage wisdom of this group: what is the proper way to index an enum by value?
My solution:
ImmutableMap<String, PresentationChannel> enumMap = Maps.uniqueIndex(ImmutableList.copyOf(PresentationChannel.values()), new Function<PresentationChannel, String>() {
public String apply(PresentationChannel input) {
return input.getChannelCode();
}});
and, in the enum:
public static PresentationChannel findByChannelCode(String channelCode) {
return enumMap.get(channelCode);
}
I think you're using non-JDK classes here right?
A similar solution with JDK API:
private static final Map<String, PresentationChannel> channels = new HashMap<String, PresentationChannel>();
static{
for (PresentationChannel channel : values()){
channels.put(channel.getChannelCode(), channel);
}
}
I wanted to get some of the sage wisdom of this group: what is the proper way to index an enum by value?
Quite possibly not doing it at all.
While hash tables provide O(1) lookup, they also have quite a large constant overhead (for hash calculations etc), so for small collections a linear search may well be faster (if "the efficient way" is your definition of "the proper way").
If you just want a DRY way to do it, I suppose Guava's Iterables.find is an alternative:
return channelCode == null ? null : Iterables.find(Arrays.asList(values()),
new Predicate<PresentationChannel>() {
public boolean apply(PresentationChannel input) {
return input.getChannelCode().equals(channelCode);
}
}, null);
Why don't you name your members A, B, C, D, E and use valueOf?
I was looking for something similar and found on this site a simple, clean and straight to the point way. Create and initialize a static final map inside your enum and add a static method for the lookup, so it would be something like:
public enum PresentationChannel {
ChannelA("A"),
ChannelB("B"),
ChannelC("C"),
ChannelD("D"),
ChannelE("E");
private String channelCode;
PresentationChannel(String channelCode) {
this.channelCode = channelCode;
}
public String getChannelCode() {
return this.channelCode;
}
private static final Map<String, PresentationChannel> lookup
= new HashMap<String, PresentationChannel>();
static {
for(PresentationChannel pc : EnumSet.allOf(PresentationChannel.class)) {
lookup.put(pc.getChannelCode(), pc);
}
}
public static PresentationChannel get(String channelCode) {
return lookup.get(channelCode);
}
}
for few values that's ok, iteration through the values array(). One note only: use smth like that. values() clones the array on each invocation.
static final PresentationChannel[] values=values();
static PresentationChannel getByCode(String code){
if (code==null)
return null;
for(PresentationChannel channel: values) if (code.equals(channel.channelCode)) return channel;
return null;
}
if you have more Channels.
private static final Map<String code, PresentationChannel> map = new HashMap<String code, PresentationChannel>();
static{//hashmap sucks a bit, esp if you have some collisions so you might need to initialize the hashmap depending on the values count and w/ some arbitrary load factor
for(PresentationChannel channel: values()) map.put(channel.channelCode, channel);
}
static PresentationChannel getByCode(String code){
return map.get(code);
}
Edit:
So implement an helper interface, like shown below, another example why java syntax generics blows and sometimes - better not used.
Usage PresentationChannel channel = EnumRepository.get(PresentationChannel.class, "A");
There will be overhead but well, it's quite fool proof.
public interface Identifiable<T> {
T getId();
public static class EnumRepository{
private static final ConcurrentMap<Class<? extends Identifiable<?>>, Map<?, ? extends Identifiable<?>>> classMap = new ConcurrentHashMap<Class<? extends Identifiable<?>>, Map<?,? extends Identifiable<?>>>(16, 0.75f, 1);
#SuppressWarnings("unchecked")
public static <ID, E extends Identifiable<ID>> E get(Class<E> clazz, ID value){
Map<ID, E> map = (Map<ID, E>) classMap.get(clazz);
if (map==null){
map=buildMap(clazz);
classMap.putIfAbsent(clazz, map);
}
return map.get(value);
}
private static <ID, E extends Identifiable<ID>> Map<ID, E> buildMap( Class<E> clazz){
E[] enumConsts = clazz.getEnumConstants();
if (enumConsts==null)
throw new IllegalArgumentException(clazz+ " is not enum");
HashMap<ID, E> map = new HashMap<ID, E>(enumConsts.length*2);
for (E e : enumConsts){
map.put(e.getId(), e);
}
return map;
}
}
}
enum X implements Identifiable<String>{
...
public String getId(){...}
}
Minor warning: if you put Identifiable somewhere out there, and many projects/wepapp depend on it (and share it) and so on, it's possible to leak classes/classloaders.
Here is another way to implement an unmodifiable map:
protected static final Map<String, ChannelCode> EnumMap;
static {
Map<String, ChannelCode> tempMap = new HashMap<String, ChannelCode>();
tempMap.put("A", ChannelA);
tempMap.put("B", ChannelB);
tempMap.put("C", ChannelC);
tempMap.put("D", ChannelD);
tempMap.put("E", ChannelE);
EnumMap = Collections.unmodifiableMap(tempMap);
}
You can use EnumMap.get(someCodeAthroughE) to quickly retrieve the ChannelCode. If the expression is null then your someCodeAthroughE was not found.
If you are expecting the provided channelCode to always be valid then you can just try and get the correct instance of the enum using the valueOf() method. If the provided value is invalid you can return null or propagate the exception.
try {
return PresentationChannel.valueOf(channelCode);
catch (IllegalArgumentException e) {
//do something.
}