jdk源码解析--WeakReference/softReference类

Posted 我的IT技术路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk源码解析--WeakReference/softReference类相关的知识,希望对你有一定的参考价值。

在之前的文中我们说过java的四种引用,强引用基本都是,虚引用基本不用,那么剩下的软引用,弱引用在平时的使用就显得有些少见,但是有时候又不得不用,本节内容我们重点说明一下软引用和弱引用的使用方法和源码解析。

 

SoftReference:

1. public class SoftReference<T> extends Reference<T> {  

2.     static private long clock;//定义一个时间戳,由垃圾回收器更新  

3.     private long timestamp;//定义一个时间戳,由调用方法进行更新  

4.     public SoftReference(T referent) {//不带引用队列的  

5.         super(referent);  

6.         this.timestamp = clock;  

7.     }  

8.     public SoftReference(T referent, ReferenceQueue<? super T> q) {//带上引用队列的  

9.         super(referent, q);  

10.         this.timestamp = clock;  

11.     }  

12.     public T get() {//调用父类的获取方法,更新timestamp  

13.         T o = super.get();  

14.         if (o != null && this.timestamp != clock)  

15.             this.timestamp = clock;  

16.         return o;  

17.     }  

18.   

19. }  

WeakReference

1. public class WeakReference<T> extends Reference<T> {  

2.     public WeakReference(T referent) {  

3.         super(referent);  

4.     }  

5.     public WeakReference(T referent, ReferenceQueue<? super T> q) {  

6.         super(referent, q);  

7.     }  

8.   

9. }  

能看到的源码部分都比较简单,现在我们通过一个实际的例子来说明一下软引用结合引用队列实现对象缓存的功能,这也是jdk中推荐的使用方法。

首先,我们创建一个利用软引用缓存的实现类:

1. import java.lang.ref.ReferenceQueue;  

2. import java.lang.ref.SoftReference;  

3. import java.util.HashMap;  

4. import java.util.Map;  

5. import java.util.Optional;  

6.   

7.   

8. public abstract class SoftReferenceCache<V> {  

9.     private  final Map<Object, SoftReferenceCls> map = new HashMap<Object,SoftReferenceCls>();  

10.     private final ReferenceQueue<V> queue = new ReferenceQueue<V>();  

11.     protected abstract Object getKeyFromValue(V v);  

12.     protected void put(V v){  

13.         clearCache();  

14.         SoftReferenceCls s = new SoftReferenceCls(v,queue);  

15.         map.put(s.key,s);  

16.     }  

17.     //本例中取不到的时候默认返回null值,在实际生产中,  

18.     // 在缓存中取不到的数据我们会去数据库进行读取,然后重新塞回缓存以保证缓存的有效性和实效性  

19.     protected V get(Object k){  

20.         clearCache();  

21.         return Optional.ofNullable(map.get(k)).map(s->s.get()).orElse(null);  

22.     }  

23.     protected void clearCache(){  

24.         SoftReferenceCls s = null;  

25.         while ((s= (SoftReferenceCls)queue.poll())!=null){  

26.             map.remove(s.key);  

27.         }  

28.     }  

29.     protected void destroy(){  

30.         clearCache();  

31.         map.clear();  

32.         System.gc();  

33.         System.runFinalization();  

34.     }  

35.   

36.     private class SoftReferenceCls extends SoftReference<V>{  

37.         private Object key ;  

38.         public SoftReferenceCls(V referent, ReferenceQueue<? super V> q) {  

39.             super(referent, q);  

40.             this.key = getKeyFromValue(referent);  

41.         }  

42.     }  

43. }  

接着我们为这个类创建一个实际要存入的缓存类:

1. public static class SoftReferenceCacheTest extends SoftReferenceCache<Person>{  //本次要存入的是person这样一个对象

2.   

3.         @Override  

4.         public Object getKeyFromValue(Person person) {  

5.             return person.getName(); //通过value和对应的k的关联关系,要确保k是唯一的 

6.         }  

7.     }  

8.   

9.     private static class Person{  

10.         private String name;  

11.         private int age;  

12.         private String sex;  

13.         private byte[] aByte = new byte[500*1024*1024]; //加这个主要是为了让大家看清楚,当内存不足的时候,软引用的value对象会被清除  

14.   

15.         public Person(String n,int a,String s){  

16.             this.age =a;  

17.             this.sex = s;  

18.             this.name = n;  

19.         }  

20.   

21.         public String getSex() {  

22.             return sex;  

23.         }  

24.   

25.         public void setSex(String sex) {  

26.             this.sex = sex;  

27.         }  

28.   

29.         public String getName() {  

30.             return name;  

31.         }  

32.   

33.         public void setName(String name) {  

34.             this.name = name;  

35.         }  

36.   

37.         public int getAge() {  

38.             return age;  

39.         }  

40.   

41.         public void setAge(int age) {  

42.             this.age = age;  

43.         }  

44.     }  

现在我们实现我们的测试代码:

1. public static void main(String[] args) {  

2.         SoftReferenceCacheTest test = new SoftReferenceCacheTest();  

3.         Person p = new Person("lily",10,"female");  

4.         test.put(p);  

5.         Optional.ofNullable(test.get("lily")).map(Person::getAge).ifPresent(System.out::println);//能打印出来  

6.         p = null;//将强引用删除  

7.         Person p1 = new Person("tom",20,"male");//申请的时候,lily的软引用也会被删除,因为内存不足  

8.         Optional.ofNullable(test.get("lily")).map(Person::getAge).ifPresent(System.out::println);//不能打印,因为lily的软引用已经被删除了  

9.   

10.     }  

好吧,基于此,我们就实现了一个利用软引用和引用队列实现的缓存功能,实现的内容还是上一节的软引用和引用队列的功能理解。到这,本节内容就结束。


以上是关于jdk源码解析--WeakReference/softReference类的主要内容,如果未能解决你的问题,请参考以下文章

HashMap putVal 源码解析-JDK1.8

JDK1.8源码解析-HashMap

JDK源码及其他框架源码解析随笔地址导航

JDK源码之HashMap源码解析

追踪解析 jdk Proxy 源码

jdk下httpserver源码解析