这种情况我们生活种经常会看到,比如访问某app某商品,第一次进去会加载一会会,后面继续点击是直接出现。
根据目前所学知识,我们可以使用 hashmap 在内存级别实现缓存功能。
例如,可以使用一个 hashmap 对象保存客户端第一次请求的结果,之后,当客户端再次发起读请求时,就从 hashmap 对象中遍历查询,如果 hashmap 中已经保存过客户要查询的数据,就直接返回,否则再向数据库发起查询请求,并将查询结果保存到 hashmap 中。
这种缓存的设计思路十分简单,但也存在一个问题:hashmap 中缓存的数据何时被清空?
内存容量是有限制的,如果永无止尽的向 hashmap 缓存数据,显然会对内存容量带来压力。一种解决方案就是使用 jvm 提供的软引用,实现对 hashmap 中缓存数据的淘汰策略。
开发中最常使用的是强引用,例如 goods goods = new goods() 就创建了一个强引用对象“goods”。只要强引用的作用域没有结束,或者没有被开发者手工设置为 null,那么强引用对象会始终存在于 jvm 内存中。
而 jvm 提供的软引用就比较灵活:当 jvm 的内存足够时,gc 对待软引用和强引用的方式是一样的;但当 jvm 的内存不足时,gc 就会去主动回收软引用对象。
可见,非常适合将缓存的对象存放在软引用中。软引用需要借助 jdk 提供的 java.lang.ref.softreference 类来实现。
项目使用idea创建一个maven项目结构如下
首先对good实体类进行编写。要求,goods有属性id,name并书写他的getset方法,以及有参无参构造器。
这里代码省略。
然后我们在goodbase里面编写代码,模拟一个数据库里面主要有hashmap,并且通过get方法,得到该hashmap
public class goodsbase { private static map<string, goods> base = new hashmap<>(); public static map<string, goods> getbase() { return base; }}
然后书写goodscache缓存类这里我们需要接触一个新关键字volatile
使用volatile关键字会强制将修改的值立即写入主存;
使用volatile关键字的话,当主线程修改时,会导致runthread的工作内存中isrunning变量的缓存值变得无效。
由于runthread的工作内存中缓存变量isrunning缓存无效,所以会再次从主存中读取isrunning变量值。
在map里面通过泛型把缓存对象存储在软引用里面(map里面)
代码如下:
public class goodscache { private volatile static goodscache goodscache; public goodscache(){ this.cache = new hashmap<>(); } public static goodscache getgoodscache() { if(goodscache == null) { synchronized (goodscache.class){ if(goodscache == null){ goodscache = new goodscache(); } } } return goodscache; } // 将缓存对象存储在软引用中 private map<string, softreference<goods>> cache; // 根据id存储缓存goods对象 public void setcache(goods goods) { cache.put(goods.getid(), new softreference<goods>(goods)); system.out.println("添加数据到缓存成功"); } // 根据id从缓存中获取对象 public goods getcache(string id) { // 根据id,获取缓存对象的软引用 softreference<goods> softref = cache.get(id); return softref == null ? null : softref.get(); } public void delcache(string id) { cache.remove(id); system.out.println("从缓存删除数据成功"); }}
goodsservice模拟数据库增删改查接下来我们书写goodsservice代码,来模拟数据库增删改查,不过我们是通过id来进行
public class goodsservice { goodscache goodscache = goodscache.getgoodscache(); public goods getbyid(string id){ if(goodscache.getcache(id) == null){ goods goods = goodsbase.getbase().get(id); goodscache.setcache(goods); system.out.println("从数据库读取数据"); system.out.println(goods.getname()); return goods; } system.out.println(goodscache.getcache(id).getname()); return goodscache.getcache(id); } public void add(goods goods){ goodscache.setcache(goods); goodsbase.getbase().put(goods.getid(), goods); system.out.println("添加数据到数据库"); } public void deletebyid(string id){ if(goodscache.getcache(id) != null){ goodscache.delcache(id); } goodsbase.getbase().remove(id); }}
最后我们书写test文件
运行结果
可以看到第二次运行 goodsservice.getbyid(1); 是从缓存中直接读取的数据,也可以看出,其实用软引用实现缓存机制,读取的对象是同一个对象。
以上就是java中如何使用软引用实现高效的缓存机制?的详细内容。
