2013-07-03 2 views
1

В guava при использовании LoadCache CacheLoader вызывается синхронно. Однако моя операция load() может занять слишком много времени (~ 1 с), я хочу принять действие по умолчанию, если оно занимает слишком много времени (> 200 мс) и загружает значение асинхронно.ЗагрузкаКата с асинхронной загрузкой

Есть ли способ достичь этого? Или есть другие подходы, которые вы можете порекомендовать?

+0

Я абсолютно уверен, что есть не способ достижения этой цели с текущим API. –

ответ

3

Вы можете просто сделать это обычным способом: отправить задачу, чтобы получить значение кеша ExecutorService, вызвать get(200, MILLISECONDS) на Future и делать что-то еще, если это время.

Пример:

final LoadingCache<Key, Result> cache = ... 
final Key key = ... 
ExecutorService executor = ... 

Future<Result> future = executor.submit(new Callable<Result>() { 
    @Override public Result call() throws Exception { 
    return cache.get(key); 
    } 
}); 

try { 
    Result result = future.get(200, TimeUnit.MILLISECONDS); 
    // got the result; do stuff 
} catch (TimeoutException timeout) { 
    // timed out; take default action 
} 
+0

Можете ли вы предоставить небольшой фрагмент кода, чтобы объяснить идею. Я не совсем понял это – aamir

+0

@AamirKhan: Добавлен упрощенный пример. – ColinD

+0

Спасибо ColidD! :) – aamir

1

Вы можете проверить, если значение равно нулю с командой getIfPresent. , если значение равно null, вы можете отправить задачу, которая загружает значения асинхронно и продолжит свой поток.

пример:

Map<String, String> map = cache.getIfPresent(key); 
if(map == null){ 
executorService.submit(new Callable<Map<String, String>>() { 
    @Override 
    public Map<String, String> call() throws Exception { 
     return cache.get(key); 
    } 
}); 
} 
else{ 
    continue with the flow... 
} 

вы должны также использовать функцию refreshAfterWrite и реализовать метод перезагрузки, если вы хотите, чтобы обновить значения в кэше, пока вы все еще читаете старое значение. В этом случае кеш всегда будет обновляться, и основной поток, который считывает значения, не будет затронут.

пример:

cache = CacheBuilder.newBuilder() 
    .refreshAfterWrite(30, TimeUnit.SECONDS) 
    .build( 
     new CacheLoader<String, Map<String,String>>() { 

      public Map<String, String> load(String key) throws Exception { 
       map = hardWork(key)//get map from from DB -- expensive time commend 
       return map; 
      } 

      @Override 
       public ListenableFuture<Map<String, String>> reload(final String key, Map<String, String> oldValue) throws Exception { 
        // we need to load new values asynchronously, so that calls to read values from the cache don't block 
        ListenableFuture<Map<String, String>> listenableFuture = executorService.submit(new Callable<Map<String, String>>() { 

         @Override 
         public Map<String, String> call() throws Exception { 
          //Async reload event 
          return load(key); 
         } 
        }); 

        return listenableFuture; 
       } 
    }); 
Смежные вопросы