caffeine高性能缓存的四种添加策略

caffeine高性能缓存的四种添加策略

caffeine 添加缓存的策略

  • 1、手动加载
  • 2、自动加载
  • 3、手动异步加载
  • 4、自动异步加载(推荐)
package com.example.demo.caffeine;

import com.alibaba.fastjson.JSON;
import com.github.benmanes.caffeine.cache.*;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;

import javax.annotation.Nullable;
import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * caffeine  添加缓存的策略
 * 1、手动加载
 * 2、自动加载
 * 3、手动异步加载
 * 4、自动异步加载(推荐)
 */
@Slf4j
public class CatchTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

//        manualLoad();
//        autoLoad();
//        manualAsyncLoad();
        autoAsyncLoad();
    }

    /**
     * ************************************************手动加载*****************************************************
     */
    public static void manualLoad() {

        Cache<String, String> cache = Caffeine.newBuilder()
                .maximumSize(10000)
                .expireAfterWrite(Duration.ofMinutes(1))
                .build();

        // 查找一个缓存元素,没有查找到的时候返回null
        String name = cache.getIfPresent("name");
        log.info("name:" + name);


        // 查找缓存,如果缓存不存在则生成缓存元素,如果无法生成则返回null[**推荐用法**]
        name = cache.get("name", k -> "小明");
        log.info("name:" + name);


        // 添加或者更新一个缓存元素
        cache.put("address", "xxx");
        String address = cache.getIfPresent("address");
        log.info("address:" + address);
    }

    /**
     * ***************************************    自动加载       *******************************************************
     * <p>
     * 支持   单个加载
     * 支持   批量加载
     * <p>
     */
    private static void autoLoad() throws InterruptedException {
        LoadingCache<String, String> cache = Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build(new CacheLoader<String, String>() {

                    @Override
                    public @Nullable String load(@NonNull String string) throws Exception {
                        log.info("load:" + string);
                        return "单个" + string;
                    }

                    @Override
                    public @NonNull Map<String, String> loadAll(@NonNull Iterable<? extends @NonNull String> keys) throws Exception {
                        log.info("loadAll:" + keys);
                        /*
                         *  默认情况下,在getAll 方法中,将会对每个不存在对应缓存的key调用一次 CacheLoader.load 来生成缓存元素。
                         * 在批量检索比单个查找更有效率的场景下,你可以覆盖并开发CacheLoader.loadAll 方法来使你的缓存更有效率。
                         * 值得注意的是,你可以通过实现一个 CacheLoader.loadAll并在其中为没有在参数中请求的key也生成对应的缓存元素。
                         * 打个比方,如果对应某个key生成的缓存元素与包含这个key的一组集合剩余的key所对应的元素一致,那么在loadAll中也可以同时加载剩下的key对应的元素到缓存当中。
                         */
                        Map<String, String> result = new HashMap<>();
                        for (String key : keys) {
                            // 模拟生成缓存数据
                            String value = "Value for " + key;
                            result.put(key, value);
                        }
                        return result;
                    }
                });
        // 查找缓存,如果缓存不存在则生成缓存元素,如果无法生成则返回null
        String name = cache.get("name");
        log.info("name:" + name);
        // 批量查找缓存,如果缓存不存在则生成缓存元素
        Map<String, String> graph = cache.getAll(Arrays.asList("t1", "t2"));
        log.info(JSON.toJSONString(graph));
    }

    /**
     * ******************************************  手动   异步加载   ***************************************
     * <p>
     * 使用自定义线程池
     */
    private static void manualAsyncLoad() throws ExecutionException, InterruptedException {
        int corePoolSize = 10; // 核心线程数
        int maximumPoolSize = 20; // 最大线程数
        long keepAliveTime = 60; // 线程空闲时间
        TimeUnit unit = TimeUnit.SECONDS; // 时间单位
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); // 任务队列
        ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );

        AsyncCache<String, String> cache = Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .executor(executor)// 可以用指定的线程池
                .buildAsync();


        CompletableFuture<String> graphxxx = cache.get("looking", new Function<String, String>() {
            @SneakyThrows
            @Override
            public String apply(String key) {
                log.info("key:" + key + ",当前线程:" + Thread.currentThread().getName());
                // 模仿从数据库获取值
                Thread.sleep(1000);
                return "异步线程获取值,然后存入缓存并返回";
            }
        });


        // 查找缓存元素,如果不存在,则异步生成
        log.info("获取name之前_time:" + System.currentTimeMillis() / 1000);
        String name = graphxxx.get();
        log.info("获取name:" + name + ",time:" + System.currentTimeMillis() / 1000);

        // 添加或者更新一个缓存元素
        cache.put("add", CompletableFuture.completedFuture("myAdd"));
        Objects.requireNonNull(cache.getIfPresent("add")).thenAccept(log::info);
    }


    /**
     * ***********************************************自动异步加载******************************************************
     * <p>
     * 支持   单个加载
     * 支持   批量加载
     * <p>
     * 注意  2.9.3 版本没有提供自定义线程池
     */
    private static AsyncLoadingCache<String, String> autoAsyncLoad() throws ExecutionException, InterruptedException {
        AsyncLoadingCache<String, String> cache = Caffeine.newBuilder()
                .maximumSize(10_000)//容量
                .expireAfterWrite(10, TimeUnit.MINUTES)//过期时间。控制键值对的有效期
                .refreshAfterWrite(Duration.ofMinutes(1))//刷新时间。异步刷新缓存中的值。
                // 当某个键被访问时,如果距离上一次刷新该键对应的值的时间已经超过了指定的刷新时间间隔,那么缓存会触发异步刷新操作。
                .buildAsync(new AsyncCacheLoader<String, String>() {
                    @Override
                    public CompletableFuture<String> asyncLoad(String key, Executor executor) {
                        return createExpensiveGraphAsync(key, executor);
                    }

                    @Override
                    public CompletableFuture<Map<String, String>> asyncLoadAll(Iterable<? extends String> keys, Executor executor) {
                        return createExpensiveGraphAsyncAll(keys, executor);
                    }
                });

        // 查找缓存元素,如果其不存在,将会异步进行生成
        cache.get("小朱").thenAccept(name -> {
            log.info("name:" + name);
        });
        // 批量查找缓存元素,如果其不存在,将会异步进行生成
        CompletableFuture<Map<String, String>> graphs = cache.getAll(Arrays.asList("k1", "k2", "k3"));
        Map<String, String> result = graphs.get();
        result.forEach((k, v) -> {
            log.info(k + "   " + v);
        });
        return cache;
    }

    /**
     * 自动异步加载----单个
     */
    private static CompletableFuture<String> createExpensiveGraphAsync(String key, Executor executor) {
        return CompletableFuture.supplyAsync(() -> {
            log.info(executor.toString());
            log.info("key:" + key + ",当前线程:" + Thread.currentThread().getName());
            return "小话";
        }, executor);
    }

    /**
     * 自动异步加载----批量
     */
    private static CompletableFuture<Map<String, String>> createExpensiveGraphAsyncAll(Iterable<? extends String> keys, Executor executor) {
        return CompletableFuture.supplyAsync(() -> {
            log.info(executor.toString());
            log.info("keys: " + keys + ", 当前线程: " + Thread.currentThread().getName());

            Map<String, String> result = new HashMap<>();
            for (String key : keys) {
                // 模拟生成缓存数据
                String value = "Value for " + key;
                result.put(key, value);
            }
            return result;
        }, executor);
    }




}

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值