重新加载同时具有并发读取器的多个缓存

时间:2016-02-04 20:25:50

标签: java multithreading caching concurrency

我使用多个哈希映射存储在类中的引用数据

Map map1;
Map map2;
Map map3;

多个读者可以同时访问它们。我想同时重新初始化它们。 如果它是一张地图,我可以做到

public void reload(){
    map1 = createNewMapWithLatestData();
}

由于现有的读者都有旧的参考资料而新的读者获得了新的参考资料,所以它的工作正常。但由于我有多个地图,新读者可能会获得最新版本的map1map2,但旧版本为map3,因为替换操作不是原子的。

好的,所以我需要把它锁定,这让我想到了我的问题。除了使用synchronized锁定所有内容之外,执行此操作的优雅方法是什么?

我只需要在重新加载实际发生时锁定,而不是在其他时间。 我查看了java locks(Read write), Conditions, CyclicBarriers, Countdownlatches等等,但不确定这是什么方法。

3 个答案:

答案 0 :(得分:1)

如果您创建新地图,那么读者无论如何都需要有办法获取新地图的参考。因此,不要直接引用mapX,而是保持对包含所有地图的对象的引用。这可以在原型上替换,因为您只需分配新的Object的引用,就像您在示例中所做的那样。不是使用map1,而是在每个地方都有holder.map1。

class Holder {
    Map map1;
    Map map2;
}

class Reader {
    Holder holder;
    void read() {
        writer.getHolder().map1.get("x");
    }
}

class Writer {
    Holder holder;
    Holder getHolder() {
        return holder;
    }
    void reload() {
        Holder newHolder = new Holder();
        newHolder.map1 = createNewMap1WithLatestData();
        newHolder.map2 = createNewMap2WithLatestData();
        holder = newHolder; // this is atomic
    }
}

答案 1 :(得分:1)

由于您希望同时使所有缓存无效,您可以

  • 按照你所说的
  • 阻止所有内容
  • 使用标志将它们设置为“无效”并禁止读者访问,直到所有这些都重新加载。如果缓存重新加载很昂贵,您可以为每个缓存设置一个标志,以指示哪个缓存无效。这实际上取决于您的申请

最优雅的选择是使用像spring cache这样的内容(如果你使用的是spring),它还管理分布式缓存

答案 2 :(得分:0)

您提供的代码量非常少,因此答案类似。是的,您需要ReadWriteLock。请阅读有关它的教程。简而言之,您始终允许阅读地图(读锁定)。但是当你想要同步他们的初始化时,你打开"写锁定,这会锁定所有可锁定的块,并且在初始化时不允许读取或写入地图。