有一段看起来像这样的代码。问题是在启动过程中会进行2次初始化。 (1)某些方法对ForumRepository进行反射并纯粹执行newInstance()来调用#setCacheEngine。 (2)随后的另一个方法调用#start()。我注意到#cache成员变量的hashCode在某些奇怪的情况下有时会有所不同。由于只有1段代码调用#setCacheEngine,因此hashCode在运行时如何更改(我假设不同的实例将具有不同的hashCode)。这里某处有错误吗?

public class ForumRepository implements Cacheable
{
    private static CacheEngine cache;
    private static ForumRepository instance;

    public void setCacheEngine(CacheEngine engine) { cache = engine; }

    public synchronized static void start()
    {
        instance = new ForumRepository();
    }

    public synchronized static void addForum( ... )
    {
        cache.add( .. );
        System.out.println( cache.hashCode() );
        // snipped
    }

    public synchronized static void getForum( ... )
    {
        ... cache.get( .. );
        System.out.println( cache.hashCode() );
        // snipped
    }
}


整个系统通过servlet的init方法进行连接和初始化。
init()方法在概念上看起来像这样:

// create an instance of the DefaultCacheEngine
cache = (CacheEngine)Class.forName( "com..DefaultCacheEngine" ).newInstance();
cache.init();

// init the ForumRepository's static member
Object o = Class.forName( "com.jforum....ForumRepository" ).newInstance();
if( o instanceof Cacheable )
    ((Cacheable)o).setCacheEngine(cache);

// Now start the ForumRepository
ForumRepository.start();


更新我没有写这段代码。它取自jforum

更新2找到解决方案。我在下面添加了单独的注释来描述问题的原因。谢谢大家。

最佳答案

您将不得不为此提供更多信息,但是CacheEngine可能是可变的数据类型,更糟糕的是,它甚至可能被其他人共享。根据CacheEngine定义其hashCode()的方式,很可能导致aForumRepository从其cache看到各种不同的哈希码。

如果相同的对象是可变的,则最好在一段时间内更改其hashCode(),只要它以一致的方式完成(这是另一个主题)。

也可以看看


Object.hashCode()-确保您了解合同的含义




cachestatic

更多信息已经浮出水面,并且我们现在知道所讨论的对象虽然可变,却没有@Override hashCode()。但是,在设计中似乎存在一个严重的问题,就是将cache设置为static类的ForumRepository字段,并使用非static“设置者” setCacheEngine(看起来是由Cacheable指定) )。

这意味着无论创建多少个cache实例,都只有ForumRepository的化身!在某种程度上,所有ForumRepository实例都“共享”相同的cache


JLS 8.3.1.1 static Fields

如果将一个字段声明为static,则无论该类最终会创建多少个实例(可能为零),都只存在该字段的一个具体化身。初始化类时,会包含一个static字段(有时称为类变量)。


我认为现在退后一步并提出以下问题很重要:


cache是否需要为static?这是故意的吗?


ForumRepository实例是否应具有自己的cache
...还是应该全部“共享”相同的cache

将创建多少个ForumRepository实例?


撇开设计模式的优缺点,ForumRepository应该是单例吗?

setCacheEngine对象可以调用多少次?


如果多次调用ForumRepository,它会从防御机制中受益吗?



最佳建议取决于上述问题的答案。第三个要点是可以立即执行的操作,可以显示IllegalStateException是否被多次调用。即使对于每个setCacheEngine实例仅对其调用一次,由于只有一个ForumRepository,在当前事务状态下,它实际上仍然是多个“集合”。

具有非cache设置符的static字段是一项设计决策,需要彻底重新检查。

10-06 06:21