guava LoadingCache学習


guava LoadingCache学習
概要
GuavaCacheを使用すると、データベースからのデータのロードなど、1つのスレッドのみが保証され、他のスレッドはそのスレッドの戻り結果を待つことができます.これにより、大量のユーザーがキャッシュの透過を要求することを回避できます.
しかし、キャッシュが期限切れになった場合、同じkeyの値を読み出すスレッドが複数ある場合、guavaは1つのスレッドだけがデータをロードし、残りのスレッドがブロックされるという致命的な欠陥もあります.これにより、大量のリクエストがキャッシュを貫通することを防止できますが、効率が低下します.refreshAfterWriteを使用すると、データをロードするスレッドのみをブロックし、残りのスレッドは古いデータを返します.
expireAfterWriteは、指定項目が一定時間内に作成/上書きされていない場合にそのkeyが削除され、次回取るときにloadingからexpireAfterAccessが指定項目が一定時間内に読み書きされていない場合にそのkeyが削除され、次回取るときにloadingからrefreshAfterWriteが指定時間内に作成/上書きされていない場合に指定時間が経過した後、再度アクセスする場合に、キャッシュはリフレッシュされ、新しい値が来ないまで古い値が返されます.キャッシュ・アイテムが取得された場合にのみ、expireとの違いは、指定された時間が経過すると、expireはremoveキーであり、次のアクセスは同期して戻り値を取得し、refreshは指定された時間後、removeキーではなく、次のアクセスはリフレッシュをトリガーし、新しい値が戻ってこない場合は古い値を返す
しかし、システム起動フェーズでは、まだ問題があります.システムが起動すると、キャッシュにデータがないため、1つのスレッドがデータをロードするとき、他のスレッドは依然としてブロックされています(古い値が返されないため).そのため、一般的なシステムが起動するときは、データをキャッシュにロードする必要があります.そうしないと、このような状況になります.
もう一つの問題は、本当にデータをロードするスレッドがブロックされるに違いありません.このロードプロセスが非同期であることを望んでいます.これにより、すべてのスレッドがすぐに古い値を返し、バックグラウンドでキャッシュデータをリフレッシュできます.refreshAfterWriteのデフォルトのリフレッシュは同期され、呼び出し元のスレッドで実行されます.CacheLoader.reload()を実現する方法で非同期に改造することができます.
コードインスタンス
public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(1);

        LoadingCache cache = CacheBuilder.newBuilder()
                .maximumSize(CACHE_SIZE)
                .refreshAfterWrite(1, TimeUnit.SECONDS)
                .build(new CacheLoader() {
                    public String load(Integer key) throws InterruptedException {
                        System.out.println(System.currentTimeMillis() + "--->" + Thread.currentThread().getName() + " load start for key: " + key);
                        System.out.println(System.currentTimeMillis() + "--->" + Thread.currentThread().getName() + " load end for key: " + key);
                        return "" + key;
                    }

                    @Override
                    public ListenableFuture reload(Integer key, String oldValue) throws Exception {
                        ListenableFutureTask task = ListenableFutureTask.create(() -> {
                            return load(key + 1);
                        });
                        executor.execute(task);
                        return task;
                    }
                });

        for (int i = 1; i < 10; i ++ ){
            int finalI = i;
            new Thread(() -> {
                try {
                    System.out.println(System.currentTimeMillis() + "--->" + Thread.currentThread().getName()  + ": get value: " + cache.get(1));
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }).start();

        }

        Thread.sleep(4000);
        System.out.println("-------------------------------------------------");

        for (int i = 1; i < 10; i ++ ){
            int finalI = i;
            new Thread(() -> {
                try {
                    System.out.println(System.currentTimeMillis() + "--->" + Thread.currentThread().getName()  + ":again get value: " + cache.get(1));
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }).start();

        }

    }

実行結果
1559298372493--->Thread-2 load start for key: 1
1559298372493--->Thread-2 load end for key: 1
1559298372478--->Thread-3: get value: 1
1559298372484--->Thread-7: get value: 1
1559298372484--->Thread-8: get value: 1
1559298372484--->Thread-9: get value: 1
1559298372483--->Thread-4: get value: 1
1559298372477--->Thread-2: get value: 1
1559298372483--->Thread-6: get value: 1
1559298372477--->Thread-1: get value: 1
1559298372483--->Thread-5: get value: 1
-------------------------------------------------
1559298376488--->Thread-13:again get value: 1
1559298376487--->Thread-12:again get value: 1
1559298376488--->Thread-14:again get value: 1
1559298376487--->Thread-11:again get value: 1
1559298376488--->Thread-15:again get value: 1
1559298376488--->Thread-16:again get value: 1
1559298376489--->Thread-17:again get value: 1
1559298376489--->Thread-18:again get value: 1
1559298376492--->pool-2-thread-1 load start for key: 2
1559298376492--->pool-2-thread-1 load end for key: 2
1559298376487--->Thread-10:again get value: 2