番石榴缓存-快速返回初始值并进行异步刷新

时间:2018-12-19 15:59:38

标签: guava

我正在尝试实现“缓存条目丰富”行为:

  1. 当缓存的密钥是新的/过时时,返回快速预先计算的值并触发密钥的异步重新计算
  2. 异步重新计算完成后,返回更新后的值

以下代码实现了这一点,但是显然很糟糕。有没有一种方法可以通过纯缓存配置来实现?

代码+测试:

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableFutureTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import lombok.SneakyThrows;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class GuavaCacheTest {

    final LoadingCache<Long, String> myCache = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .build(
                    new CacheLoader<Long, String>() {

                        ExecutorService executor = Executors.newFixedThreadPool(10);

                        public String load(Long key) {
                            System.out.println("load() " + key);
                            return "INITIAL";
                        }

                        public ListenableFuture<String> reload(final Long key, String prevString) {
                            // asynchronous!
                            ListenableFutureTask<String> task = ListenableFutureTask.create(() -> {
                                System.out.println("reload() started for ... " + key);

                                try {
                                    Thread.sleep(1000);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }

                                System.out.println("reload() ended for ... " + key);

                                return "Calculated value for " + key;

                            });
                            executor.execute(task);
                            return task;
                        }

                    });


    public String myget(Long key) {
        String v = myCache.getUnchecked(key);

        if (v == "INITIAL") {
            myCache.refresh(key);
            myCache.getUnchecked(key);

            v = "Initial value for " + key;
        }

        return v;
    }

    @Test
    @SneakyThrows
    public void testRepeatedCalls() {


        System.out.println("Call result: " + myget(55L));
        System.out.println("Call result: " + myget(55L));
        System.out.println("Call result: " + myget(55L));
        System.out.println("Call result: " + myget(55L));

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("---------------");

        System.out.println("Call result: " + myget(55L));
        System.out.println("Call result: " + myget(55L));
        System.out.println("Call result: " + myget(55L));
        System.out.println("Call result: " + myget(55L));

    }

}

输出:

load() 55
reload() started for ... 55
Call result: Initial value for 55
Call result: Initial value for 55
Call result: Initial value for 55
Call result: Initial value for 55
reload() ended for ... 55
---------------
Call result: Calculated value for 55
Call result: Calculated value for 55
Call result: Calculated value for 55
Call result: Calculated value for 55

0 个答案:

没有答案