Reputation: 987
I have a generic class that can be sketched like this
public class Shared<T extends EntityBase> {
private HashMap<String, Class<? extends Executor<T>>> classes;
private HashMap<String, ? super Executor<T>> instances;
private List<Entity> entities;
private Compiler compiler;
// Constructor and getters
public void put(Entity entity, Source source) {
Class<?> cls = compiler.load(source);
put(entity, (Class<? extends Executor<T>>) cls );
}
private void put(Entity entity, Class<? extends Executor<T>> cls) throws IllegalAccessException, InstantiationException {
classes.put(entity.getId(), cls);
instances.put(entity.getId(), cls.newInstance());
entities.add(entity);
}
}
In my application this class is instanced once and several independent threads access it.
In particular a single thread is responsible of writing to it and several access its instances Map via a getter.
When I receive a Source
instance and call the private put
method, both maps and the list are updated.
In a debugging session with InteliiJ
when the frame of the Singleton
class is exited the this class losses its state and both Map
and the List
became empty once again.
How may I explain that? Why the Class<? extends Executor<T>>
instances and the ? super Executor<T>
instances are lost?
Upvotes: 0
Views: 29
Reputation: 103244
generics are effectively just part of the compiler's imagination; at runtime that's all gone. Therefore, the generics in this example have absolutely nothing to do with what you're witnessing.
The code as pasted cannot produce the effect you see (where the map first changes, then reverts). But, more generally, if you are calling 'put' from different threads, this code is broken. There are no guards in place to prevent synchronous access. When you update a map simultaneously from different threads, the map spec specifically says anything can happen (In that sense, the map just resetting to empty is technically 'according to spec', in that anything is allowed because you're not doing the threading issue right).
The easy fix is to mark your second put method as 'synchronized'.
An alternative strategy is to use lists and maps from the java.util.concurrent
package. However, no amount of using that will ever let you have classes
, instances
and entities
be guaranteed in sync with each other. Only synchronized
can do that.
Upvotes: 1