使用长时间运行的值计算进行缓存

时间:2014-11-09 19:39:44

标签: java caching concurrency java.util.concurrent

我需要将对象存储在缓存中,并且这些对象需要很长时间才能创建。我从ConcurrentHashMap<id, Future<Object>>开始,一切都很好,直到Out of Memory开始发生。转移到SoftReferences,它更好,但现在我需要控制驱逐。我正在搬到Ehcache。

我确定有一个库用于这样的事情但我真的需要理解在两个阶段进行缓存存储和计算的逻辑,同时保持一致性并且不重新计算已经计算过的东西或者计算过程。是一个两级缓存,一个用于更持久的结果,另一个用于计算过程。

有关如何改进以下代码的任何提示,我确信Callable.call()方法中存在并发问题?

public class TwoLevelCache {

    // cache that serializes everything except Futures
    private Cache complexicos = new Cache();

    private ConcurrentMap<Integer, Future<Complexixo>> calculations = 
        new ConcurrentHashMap<Integer, Future<Complexico>>();

    public Complexico get(final Integer id) {

        // if in cache return it
        Complexico c = complexicos.get(id);
        if (c != null) { return c; }

        // if in calculation wait for future
        Future f = calculations.get(id);
        if (f != null) { return f.get(); } // exceptions obviated

        // if not, setup calculation
        Callable<Complexico> callable = new Callable<Complexico>() {
            public Complexico call() throws Exception {
                Complexico complexico = compute(id);
                // this might be a problem here
                // but how to synchronize without
                // blocking the whole structure?
                complexicos.put(id, complexico);
                calculations.remove(id);
                return complexico;
            }
        };

        // store calculation 
        FutureTask<Complexico> task = new FutureTask<Complexico>(callable);
        Future<Complexico> future = futures.putIfAbsent(id, task);
        if (future == null) {
            // not previosly being run, so start calculation
            task.run();
            return task.get(); // exceptions obviated
        } else {
            // there was a previous calculation, so use that
            return future.get(); // exceptions obviated
        }

    }

    private Complexico compute(final Integer id) { 
        // very long computation of complexico
    }

}

1 个答案:

答案 0 :(得分:0)

一旦计算出来,你对这些值做了什么? 每秒新计算的数量是多少?

如果使用(存储)然后处理它们,那么我认为Reactive方法(RxJava和类似方法)可能是一个很好的解决方案。你可以把你的任务和#34; (一个POJO,包含执行计算所需的所有信息)在一些堆外结构(它可能是一些持久队列等),并且只执行任意数量的计算(用你想要的计算线程的数量限制进程)有)。

通过这种方式,您可以避免使用OOM,并且可以更好地控制整个过程。