2014-11-09 6 views
0

캐시에 개체를 저장해야하며 개체를 만드는 데 시간이 오래 걸릴 수 있습니다. ConcurrentHashMap<id, Future<Object>>으로 시작하여 메모리 부족이 발생할 때까지 모든 것이 잘되었습니다. SoftReferences로 이동하고 더 좋았지 만 지금은 퇴거를 제어해야합니다. Ehcache로 이사 중입니다.값이 오랫동안 계산되는 캐시

확실한 라이브러리가있을 것이라고 확신하지만 모든 것을 일관되게 유지하면서 이미 계산되거나 처리중인 것을 다시 계산하지 않으면 서 캐시 스토리지와 계산을 2 단계로 수행하는 논리를 이해해야합니다. 계산 중입니다. 두 개의 레벨 캐시, 하나는 더 지속적인 결과를, 다른 하나는 계산 과정에 사용됩니다.

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 
    } 

} 
+0

Java 8의 ['Map.computeIfAbsent'] (https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util)를 사용할 수 있습니다. function.Function-)을'ConcurrentHashMap'과 함께 사용하면 코드를 깔끔하게 정리할 수 있습니다. 'Callable.call'은 확실히 약간의 재난 지역입니다. –

+0

미래를 만들고 그 결과를 얻는데 얼마나 걸리나요? –

+0

@ R4J 그것은 0.1 초에서 10 초까지 걸립니다. – rmarimon

답변

0

계산 된 값으로 무엇을합니까? 초당 새로운 계산의 수는 얼마입니까?

그들이 사용 (저장) 된 다음 폐기 된 경우 Reactive (RxJava 및 유사) 접근 방식이 좋은 해결책이 될 수 있다고 생각합니다. 당신은 당신의 "작업"(계산을 수행하는 데 필요한 모든 정보가있는 POJO)을 일부 힙 구조 (일부 영속 대기열 등이 될 수 있음)에 배치하고 원하는만큼 계산을 수행 할 수 있습니다. 계산 스레드 수).

이렇게하면 OOM을 피할 수 있고 전체 프로세스를 훨씬 더 제어 할 수 있습니다.

+0

값은 노드 구조 사이의 경로입니다. 포인터는 일반적으로 매우 작은 데이터 인 노드 간의 최소 거리입니다. 가능한 한 오랫동안 이러한 경로를 기억해야합니다. – rmarimon

+0

JVM의 힙은 이러한 양의 데이터를 유지하는 데 많은 비용이 듭니다. Redis와 같은 몇몇 종류의 K/V 상점을 생각해보아야합니까? –