我有一个通用类,可以像这样素描
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);
}
}
在我的应用程序中,该类被一次实例化,并且有多个独立的线程对其进行访问。
特别是,一个线程负责对其进行写入,并通过getter对其多个实例Map进行访问。
当我收到一个Source
实例并调用private put
方法时,地图和列表都将更新。
在与InteliiJ
的调试会话中,当Singleton
类的 frame 退出时,该类将丢失其状态,并且Map
和{{ 1}}再次变空。
我该怎么解释?为什么List
实例和Class<? extends Executor<T>>
实例丢失了?
答案 0 :(得分:1)
泛型实际上只是编译器想象力的一部分;在运行时,一切都消失了。因此,本例中的泛型与您目睹的绝对无关。
粘贴的代码无法产生您所看到的效果(地图先更改,然后还原)。但是,更一般而言,如果您从不同的线程调用“ put”,则此代码将被破坏。没有防护措施来防止同步访问。当您从不同的线程同时更新地图时,地图规范明确指出可能发生任何事情(从这种意义上说,仅重置为空的地图在技术上是“根据规范”的,因为不允许任何操作,因为您没有在执行线程发行权)。
简单的解决方法是将第二个put方法标记为“已同步”。
另一种策略是使用java.util.concurrent
包中的列表和映射。但是,没有任何使用量会让您保证classes
,instances
和entities
彼此同步。只有synchronized
可以做到。