当前位置:首页 > 人工智能

面试官:你是如何使用JDK来实现自己的缓存(支持高并发)?

需求分析

项目中经常会遇到这种场景:一份数据需要在多处共享,面试有些数据还有时效性,官何高并过期自动失效。使用K实比如手机验证码,现自发送之后需要缓存起来,缓存然后处于安全性考虑,支持一般还要设置有效期,面试到期自动失效。官何高并我们怎么实现这样的使用K实功能呢?

解决方案

 使用现有的缓存技术框架,比如redis,现自ehcache。优点:成熟,缓存稳定,支持功能强大;缺点,面试项目需要引入对应的官何高并框架,不够轻量。网站模板使用K实  如果不考虑分布式,只是在单线程或者多线程间作数据缓存,其实完全可以自己手写一个缓存工具。下面就来简单实现一个这样的工具。

先上代码: 

import java.util.HashMap;  import java.util.Map;  import java.util.concurrent.*;  /**   * @Author: lixk   * @Date: 2018/5/9 15:03   * @Description: 简单的内存缓存工具类   */  public class Cache {    //键值对集合   private final static Map<String, Entity> map = new HashMap<>();   //定时器线程池,用于清除过期缓存   private final static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();   /**   * 添加缓存   *   * @param key 键   * @param data 值   */   public synchronized static void put(String key, Object data) {    Cache.put(key, data, 0);   }   /**   * 添加缓存   *   * @param key 键   * @param data 值   * @param expire 过期时间,单位:毫秒, 0表示***长   */   public synchronized static void put(String key, Object data, long expire) {    //清除原键值对   Cache.remove(key);   //设置过期时间   if (expire > 0) {    Future future = executor.schedule(new Runnable() {    @Override   public void run() {    //过期后清除该键值对   synchronized (Cache.class) {    map.remove(key);   }   }   }, expire, TimeUnit.MILLISECONDS);   map.put(key, new Entity(data, future));   } else {    //不设置过期时间   map.put(key, new Entity(data, null));   }   }   /**   * 读取缓存   *   * @param key 键   * @return   */   public synchronized static Object get(String key) {    Entity entity = map.get(key);   return entity == null ? null : entity.getValue();   }   /**   * 读取缓存   *   * @param key 键   * * @param clazz 值类型   * @return   */   public synchronized static <T> T get(String key, Class<T> clazz) {    return clazz.cast(Cache.get(key));   }   /**   * 清除缓存   *   * @param key   * @return   */   public synchronized static Object remove(String key) {    //清除原缓存数据   Entity entity = map.remove(key);   if (entity == null) return null;   //清除原键值对定时器   Future future = entity.getFuture();   if (future != null) future.cancel(true);   return entity.getValue();   }   /**   * 查询当前缓存的键值对数量   *   * @return   */   public synchronized static int size() {    return map.size();   }   /**   * 缓存实体类   */   private static class Entity {    //键值对的value   private Object value;   //定时器Future    private Future future;   public Entity(Object value, Future future) {    this.value = value;   this.future = future;   }   /**   * 获取值   *   * @return   */   public Object getValue() {    return value;   }   /**   * 获取Future对象   *   * @return   */   public Future getFuture() {    return future;   }   }  } 

本工具类主要采用 HashMap+定时器线程池 实现,map 用于存储键值对数据,map的value是 Cache 的云南idc服务商内部类对象 Entity,Entity 包含 value 和该键值对的生命周期定时器 Future。Cache 类对外只提供了 put(key, value), put(key, value, expire), get(key), get(key, class), remove(key), size()几个同步方法。

当添加键值对数据的时候,首先会调用remove()方法,清除掉原来相同 key 的数据,并取消对应的定时清除任务,然后添加新数据到 map 中,并且,如果设置了有效时间,则添加对应的定时清除任务到定时器线程池。

测试 

import java.util.concurrent.ExecutionException;  import java.util.concurrent.ExecutorService;  import java.util.concurrent.Executors;  import java.util.concurrent.Future;  /**   * @Author: lixk   * @Date: 2018/5/9 16:40   * @Description: 缓存工具类测试   */  public class CacheTest {    /**   * 测试   *   * @param args   */   public static void main(String[] args) throws InterruptedException, ExecutionException {    String key = "id";   //不设置过期时间   System.out.println("亿华云

分享到:

滇ICP备2023006006号-16