千家信息网

如何使用JDK来实现自己的缓存

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章给大家介绍如何使用JDK来实现自己的缓存,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。需求分析项目中经常会遇到这种场景:一份数据需要在多处共享,有些数据还有时效性,过期自
千家信息网最后更新 2026年11月01日如何使用JDK来实现自己的缓存

这篇文章给大家介绍如何使用JDK来实现自己的缓存,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

需求分析

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

解决方案

  1. 使用现有的缓存技术框架,比如redis,ehcache。优点:成熟,稳定,功能强大;缺点,项目需要引入对应的框架,不够轻量。

  2. 如果不考虑分布式,只是在单线程或者多线程间作数据缓存,其实完全可以自己手写一个缓存工具。下面就来简单实现一个这样的工具。

先上代码:

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 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 get(String key, Class 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 的内部类对象 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("***********不设置过期时间**********");   Cache.put(key, 123);   System.out.println("key:" + key + ", value:" + Cache.get(key));   System.out.println("key:" + key + ", value:" + Cache.remove(key));   System.out.println("key:" + key + ", value:" + Cache.get(key));   //设置过期时间   System.out.println("  ***********设置过期时间**********");   Cache.put(key, "123456", 1000);   System.out.println("key:" + key + ", value:" + Cache.get(key));   Thread.sleep(2000);   System.out.println("key:" + key + ", value:" + Cache.get(key));   /******************并发性能测试************/   System.out.println("  ***********并发性能测试************");   //创建有10个线程的线程池,将1000000次操作分10次添加到线程池   ExecutorService executorService = Executors.newFixedThreadPool(10);   Future[] futures = new Future[10];   /********添加********/   {   long start = System.currentTimeMillis();   for (int j = 0; j < 10; j++) {   futures[j] = executorService.submit(() -> {   for (int i = 0; i < 100000; i++) {   Cache.put(Thread.currentThread().getId() + key + i, i, 300000);   }   });   }   //等待全部线程执行完成,打印执行时间   for (Future future : futures) {   future.get();   }   System.out.printf("添加耗时:%dms  ", System.currentTimeMillis() - start);   }   /********查询********/   {   long start = System.currentTimeMillis();   for (int j = 0; j < 10; j++) {   futures[j] = executorService.submit(() -> {   for (int i = 0; i < 100000; i++) {   Cache.get(Thread.currentThread().getId() + key + i);   }   });   }   //等待全部线程执行完成,打印执行时间   for (Future future : futures) {   future.get();   }   System.out.printf("查询耗时:%dms  ", System.currentTimeMillis() - start);   }   System.out.println("当前缓存容量:" + Cache.size());   }  }

测试结果:

***********不设置过期时间**********  key:id, value:123  key:id, value:123  key:id, value:null  ***********设置过期时间**********  key:id, value:123456  key:id, value:null  ***********并发性能测试************  添加耗时:2313ms  查询耗时:335ms  当前缓存容量:1000000

测试程序使用有10个线程的线程池来模拟并发,总共执行一百万次添加和查询操作,时间大约都在两秒多,表现还不错,每秒40万读写并发应该还是可以满足大多数高并发场景的^_^

关于如何使用JDK来实现自己的缓存就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

缓存 时间 线程 数据 测试 定时器 工具 查询 性能 不错 有效 任务 内容 功能 场景 容量 对象 方法 更多 框架 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 中关村互联网科技集团 科技和互联网公司 互联网 科技公司 互联网公司 科技公司 鑫亿盛互联网科技 碳银互联网科技有限公司 火传媒上海互联网科技 互联网科技有限公司 翻译 汉立互联网科技有限公司联系电话 互联网科技创新服务 厦门比较好的科技互联网公司 移动互联网年度科技创新 想开互联网科技公司怎么样 爱医互联网络科技 工业互联网展湾科技股份有限公司 2021互联网科技公司排名 银川新华互联网科技学校原画 美国五大互联网科技公司市值多少 北京瑞云互联网科技有限公司 恒生科技互联网指数十大成分股 万易互联网科技有限公司 中国互联网有什么科技含量 欧洲十大科技互联网公司 互联网经济与金融科技 互联网科技公司营业执照怎么办理 华中科技大学互联网的牛人 广州千川互联网科技有限公司 美国互联网科技公司 科技互联网经济论坛 每日互联网科技新闻
0