具有多线程和实例共享的泛型

时间:2019-01-24 18:20:10

标签: java generics garbage-collection

我有一个通用类,可以像这样素描

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>>实例丢失了?

1 个答案:

答案 0 :(得分:1)

泛型实际上只是编译器想象力的一部分;在运行时,一切都消失了。因此,本例中的泛型与您目睹的绝对无关。

粘贴的代码无法产生您所看到的效果(地图先更改,然后还原)。但是,更一般而言,如果您从不同的线程调用“ put”,则此代码将被破坏。没有防护措施来防止同步访问。当您从不同的线程同时更新地图时,地图规范明确指出可能发生任何事情(从这种意义上说,仅重置为空的地图在技术上是“根据规范”的,因为不允许任何操作,因为您没有在执行线程发行权)。

简单的解决方法是将第二个put方法标记为“已同步”。

另一种策略是使用java.util.concurrent包中的列表和映射。但是,没有任何使用量会让您保证classesinstancesentities彼此同步。只有synchronized可以做到。