【java】本地(内存)缓存实战--LocalCacheUtil.java

平凡也就两个字: 懒和惰;
成功也就两个字: 苦和勤;
优秀也就两个字: 你和我。
跟着我从0学习JAVA、spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美!
关注微信公众号【 IT特靠谱 】,每天都会分享技术心得~

【java】本地(内存)缓存实战--LocalCache

      数据缓存有多种方式,也有不同存储媒介。如redis、cookie、session、memcache等,这里却要说的是一种存储在内存中的对象缓存,这里称为:LocalCache。

     闲话少说,重点都在代码里面!

1 缓存工具类

      我把实现本地缓存的代码整理形成了一个java工具类:LocalCacheUtil.java。

      1)调用save()方法,可以添加缓存,并指定过期时间。

      2)调用load()方法可以从本地缓存中读取数据,如果缓存过期了,则返回null,业务层需要从数据库等持久化存储库中查询数据,并再次缓存起来。

      3)也可以调用clearCache()方法手动删除指定key缓存。

      4)定时任务会每隔5分钟定时清理一次已过期的缓存数据。

package com.hc.alltest.localCache;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * 本地内存缓存工具类
 */
@Slf4j
public class LocalCacheUtil {

  private LocalCacheUtil() {

  }

  // 定时任务执行器
  private static ScheduledExecutorService refreshExecutor = new ScheduledThreadPoolExecutor(1, Executors.defaultThreadFactory());

  // 当前缓存
  private static volatile ConcurrentHashMap<String, CacheElement<Object>> cacheMap = new ConcurrentHashMap<>();

  // 缓存对象
  static class CacheElement<T extends Object> {

    // 缓存值
    private T value;

    // 过期时间
    private Long expire;

    /**
     * 有参数构造方法
     *
     * @param value 缓存的值
     * @param timeout 过期时间。单位:ms
     */
    public CacheElement(T value, Long timeout) {
      this.value = value;
      this.expire = System.currentTimeMillis() + timeout;
    }

    /**
     * 判断缓存是否过期
     */
    public boolean isOvertime() {
      return expire < System.currentTimeMillis();
    }
  }

  /**
   * 读取本地缓存
   *
   * @param key 缓存key
   * @param requireClass 缓存值对应class
   */
  public static <T extends Object> T load(String key, Class<T> requireClass) {
    CacheElement<Object> e = cacheMap.get(key);
    //过期返回null
    if (null == e || e.isOvertime()) {
      return null;
    }
    return TypeUtils.cast(e.value, requireClass, ParserConfig.getGlobalInstance());
  }

  /**
   * 保存至本地缓存
   *
   * @param key 缓存key
   * @param value 缓存值
   * @param timeout 过期时间。单位:ms
   */
  public static <T extends Object> void save(String key, T value, Long timeout) {
    cacheMap.put(key, new CacheElement<>(value, timeout));
  }

  /**
   * 手动清除key对应的本地缓存
   */
  public static void clearCache(String key) {
    cacheMap.put(key, null);
  }

  /**
   * 定时(每5分钟)清理一次缓存中过期的数据
   */
  static {
    refreshExecutor.scheduleAtFixedRate(() -> {
      ConcurrentHashMap<String, CacheElement<Object>> newCache = new ConcurrentHashMap<>();
      for (Map.Entry<String, CacheElement<Object>> e : cacheMap.entrySet()) {
        // 丢弃已经过期的数据
        if (e.getValue().isOvertime()) {
          continue;
        }
        newCache.put(e.getKey(), e.getValue());
      }
      cacheMap = newCache;
    }, 0, 5 * 60, TimeUnit.SECONDS);
  }
}

2 测试本地缓存

      往本地缓存中缓存一个键为:name,值为:张三 的数据。然后循环从本地缓存中读取name键对应的缓存数据。

package com.hc.alltest.localCache;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

/**
 * 测试本地缓存
 */
@Slf4j
public class Main {

  public static void main(String[] args) throws Exception {
    //缓存数据
    LocalCacheUtil.save("name", "张三", 600L);
    while (true) {
      //从缓存读取数据
      String cacheValue = LocalCacheUtil.load("name", String.class);
      log.info("cacheValue:" + cacheValue);
      if(StringUtils.isEmpty(cacheValue)){
        break;
      }
      Thread.sleep(100L);
    }
  }
}

      关注微信公众号,免费获取java及其相关视频教程~

 

猜你喜欢

转载自blog.csdn.net/IT_Most/article/details/109169416