本文章是基于https://www.cnblogs.com/Skyar/p/5962253.html基础上修改而来。在其基础上优化了一下。添加了一些代码。若有问题,请告知我。及时修改html
首先分清楚三个概念java
强引用、软引用、弱引用、数据库
1.强引用缓存
指向经过new获得的内存空间的引用叫强引用。好比有String a = newString(“123”);,其中的a就是一个强引用,它指向了一块内容是123的堆空间。数据结构
2.软引用ide
若是一个对象只具备软引用,而当前虚拟机堆内存空间足够,那么垃圾回收器就不会回收它,反之就会回收这些软引用指向的对象。性能
3.弱引用测试
与软引用的区别在于,垃圾回收器一旦发现某块内存上只有弱引用(必定请注意只有弱引用,没强引用),无论当前内存空间是否足够,那么都会回收这块内存。优化
2、强引用、软引用demo网站
1 import java.lang.ref.SoftReference; 2 import java.lang.ref.WeakReference; 3 public class ReferenceDemo { 4 public static void main(String[] args) { 5 // 强引用 6 String str=new String("abc"); 7 SoftReference<String> softRef=new SoftReference<String>(str); // 软引用 8 str = null; // 去掉强引用 9 System.gc(); // 垃圾回收器进行回收 10 System.out.println(softRef.get()); 11 // 强引用 12 String abc = new String("123"); 13 WeakReference<String> weakRef=new WeakReference<String>(abc); // 弱引用 14 abc = null; // 去掉强引用 15 System.gc(); // 垃圾回收器进行回收 16 System.out.println(weakRef.get()); 17 } 18 }
3、使用场景
1.软引用的使用场景
好比在一个博客管理系统里,为了提高访问性能,在用户在点击博文时,若是这篇博文没有缓存到内存中,则须要作缓存动做,这样其它用户在点击一样这篇文章时,就能直接从内存里装载,而不用走数据库,这样能下降响应时间。
咱们能够经过数据库级别的缓存在作到这点,这里也能够经过软引用来实现,具体的实现步骤以下。
第一,能够经过定义Content类来封装博文的内容,其中能够包括文章ID、文章内容、做者、发表时间和引用图片等相关信息。
第二,能够定义一个类型为HashMap<String, SoftReference<Content>>的对象类保存缓存内容,其中键是String类型,表示文章ID,值是指向Content的软引用。
第三,当用户点击某个ID的文章时,根据ID到第二步定义的HashMap里去找,若是找到,并且所对应的SoftReference<Content>值内容不是null,则直接从这里拿数据并作展现动做,这样不用走数据库,能够提高性能。
第四,若是用户点击的某个文章的ID在HashMap里找不到,或者虽然找到,但对应的值内容是空,那么就从数据库去找,找到后显示这个文章,同时再把它插入到HashMap里,这里请注意,显示后须要撤销掉这个Content类型对象上的强引用,保证它上面只有一个软引用。
来分析下用软引用有什么好处?假设咱们用1个G的空间缓存了10000篇文章,这10000篇文章所占的内存空间上只有软引用。若是内存空间足够,那么咱们能够经过缓存来提高性能,但万一内存空间不够,咱们能够依次释放这10000篇文章所占的1G内存,释放后不会影响业务流程,最多就是下降些性能。
对比一下,若是咱们这里不用软应用,而是用强引用来缓存,因为不知道文章什么时候将被点击,咱们还没法得知何时能够撤销这些文章对象上的强引用,或者即便咱们引入了一套缓存淘汰流程,但这就是额外的工做了,这就没刚才使用“软引用“那样方便了。
2.经过WeakHashMap来了解弱引用的使用场景
WeakHashMap和HashMap很类似,能够存储键值对类型的对象,但咱们能够从它的名字上看出,其中的引用是弱引用。经过下面的WeakHashMapDemo.java,咱们来看下它的用法。
1 import java.util.HashMap; 2 import java.util.Iterator; 3 import java.util.Map; 4 import java.util.WeakHashMap; 5 public class WeakHashMapDemo { 6 public static void main(String[] args) throws Exception { 7 String a = new String("a"); 8 String b = new String("b"); 9 Map weakmap = new WeakHashMap(); 10 Map map = new HashMap(); 11 map.put(a, "aaa"); 12 map.put(b, "bbb"); 13 weakmap.put(a, "aaa"); 14 weakmap.put(b, "bbb"); 15 map.remove(a); 16 a=null; 17 b=null; 18 System.gc(); 19 Iterator i = map.entrySet().iterator(); 20 while (i.hasNext()) { 21 Map.Entry en = (Map.Entry)i.next(); System.out.println("map:"+en.getKey()+":"+en.getValue()); 22 } 23 Iterator j = weakmap.entrySet().iterator(); 24 while (j.hasNext()) { 25 Map.Entry en = (Map.Entry)j.next();System.out.println("weakmap:"+en.getKey()+":"+en.getValue()); 26 } 27 } 28 }
行号 |
针对内存的操做以及输出结果 |
7 |
在堆空间里分配一块空间(假设首地址是1000),在其中写入String类型的a,并用a这个强引用指向这块空间。 |
8 |
在堆空间里分配一块空间(假设首地址是2000),在其中写入String类型的b,并用b这个强引用指向这块空间。 |
11,12 |
在HashMap里了插入两个键值对,其中键分别是a和b引用,这样1000号和2000号内存上就分别多加了一个强引用了(有两个强引用了)。 |
13,14 |
在WeakHashMap里了插入两个键值对,其中键分别是a和b引用,这样1000号和2000号内存上就分别多加了一个弱引用了(有两个强引用,和一个弱引用)。 |
15 |
从HashMap里移出键是a引用的键值对,这时1000号内存上有一个String类型的强引用和一个弱引用。 |
16 |
撤销掉1000号内存上的a这个强引用,此时1000号内存上只有一个弱引用了。 |
17 |
撤销掉2000号内存上的b这个强引用,此时2000号内存上有一个HashMap指向的强引用和一个WeakHashMap指向的弱引用。 |
18 |
经过System.gc()回收内存 |
19~22 |
遍历并打印HashMap里的对象,这里争议不大,在11和12行放入了a和b这两个强引用的键,在第15行移出a,因此会打印map:b:bbb。 |
23~25 |
遍历并打印WeakHashMap里的对象,这里的输出是weakmap:b:bbb。 虽然咱们没有从WeakHashMap里移除a这个引用,但以前a所对应的1000号内存上的强引用全都已经被移除,只有一个弱引用,因此在第18行时,1000号内存里的内存已经被回收,因此WeakHashMap里也看不到a了,只能看到b。 |
3. 弱引用的使用场景2
好比在某个电商网站项目里,咱们会用Coupan这个类来保存优惠券信息,在其中咱们能够定义优惠券的打折程度,有效日期和所做用的商品范围等信息。当咱们从数据库里获得全部的优惠券信息后,会用一个List<Coupan>类型的coupanList对象来存储全部优惠券。
并且,咱们想要用一种数据结构来保存一个优惠券对象以及它所关联的全部用户,这时咱们能够用WeakHashMap<Coupan, <List<WeakReference <User>>>类型的weakCoupanHM对象。其中它的键是Coupan类型,值是指向List<User>用户列表的弱引用。
你们能够想象下,若是有100个优惠券,那么它们会存储于List<Coupan>类型的coupanList,同时,WeakHashMap<Coupan, <List<WeakReference <User>>>类型的weakCoupanHM对象会以键的形式存储这100个优惠券。并且,若是有1万个用户,那么咱们能够用List<User>类型的userList对象来保存它们,假设coupan1这张优惠券对应着100个用户,那么咱们必定会经过以下的代码存入这种键值对关系,weakCoupanHM.put(coupan1,weakUserList);,其中weakUserList里以弱引用的方式保存coupan1所对应的100个用户。
这样的话,一旦当优惠券或用户发生变动,它们的对应关系就能自动地更新,具体表现以下。
1 当某个优惠券(假设对应于coupan2对象)失效时,咱们能够从coupanList里去除该对象,coupan2上就没有强引用了,只有weakCoupanHM对该对象还有个弱引用,这样coupan2对象能在下次垃圾回收时被回收,从而weakCoupanHM里就看不到了。
2 假设某个优惠券coupan3用弱引用的方式指向于100个用户,当某个用户(假设user1)注销帐号时,它会被从List<User>类型的userList对象中被移除。这时该对象上只有weakCoupanHM里的值(也就是<List<WeakReference <User>>)这个弱引用,该对象一样能在下次垃圾回收时被回收,这样coupan3的关联用户就会自动地更新为99个。
若是不用弱引用,而是用常规的HashMap<Coupan,List<User>>来保存对应关系的话,那么一旦出现优惠券或用户的变动的话,那么咱们就不得不手动地更新这个表示对应关系的HashMap对象了,这样,代码就会变得复杂,并且咱们颇有可能因疏忽而忘记在某个位置添加更新代码。相比之下,弱引用给咱们带来的“自动更新“就能给咱们带来很大的便利。
/*** * 用户 */ public class User { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } }
/** * 优惠券 */ public class Coupan { private String coupanName; public String getCoupanName() { return coupanName; } public void setCoupanName(String coupanName) { this.coupanName = coupanName; } @Override public String toString() { return "Coupan{" + "coupanName='" + coupanName + '\'' + '}'; } }
import java.lang.ref.WeakReference; import java.util.*; public class TestCoupan { public static void main(String[] args) { WeakHashMap<Coupan, List<WeakReference<User>>> weakCoupanHM = new WeakHashMap<>(); List<Coupan> coupans = new ArrayList<>(); List<User> users = new ArrayList<>(); for (int i = 1 ; i< 100 ; i ++){ Coupan coupan = new Coupan(); coupan.setCoupanName("优惠券编码>"+i); coupans.add(coupan); } for (int i = 1; i < 10000; i++){ User user = new User(); user.setName("用户>"+i); users.add(user); } List<WeakReference<User>> weakUsers = new ArrayList<>(); for (int i = 0; i < 10; i++) { User u = users.get(i); WeakReference<User> weakUser = new WeakReference<User>(u); ; weakUsers.add(weakUser); } weakCoupanHM.put(coupans.get(1),weakUsers); printWeakCoupanHM(weakCoupanHM); // coupans.remove(1); //能够用这一行测试优惠券 users.remove(1); System.gc(); printWeakCoupanHM(weakCoupanHM); } private static void printWeakCoupanHM(WeakHashMap<Coupan, List<WeakReference<User>>> weakCoupanHM){ Iterator<Map.Entry<Coupan, List<WeakReference<User>>>> weakCoupanItr = weakCoupanHM.entrySet().iterator(); while(weakCoupanItr.hasNext()){ Map.Entry<Coupan, List<WeakReference<User>>> entry = weakCoupanItr.next(); Coupan coupan = entry.getKey(); System.out.println(coupan); for (WeakReference<User> weakU: entry.getValue() ) { System.out.println(weakU.get()); } } } }
研读过程当中,画了一些草图,但愿对读者有必定的帮助