Java 引用类解析

JVM的垃圾回收机制,就是清除无用对象所占用的空间,以及修复堆中碎片空间的机制。它根据对象的可达性来判断一个对象是否为“垃圾”。对象的可达性就是可触及性,它根据从根节点出发,是否能够到达对象,如果不能,就是不可触及,将回收。根节点的节点如常量池,方法中的本地变量等。可触及性分为四个程度:

1. 强可触及。根节点能够引用到该对象,如 String str = new String("123");就为创建了一个强克触及对象str,str指向堆内存创建的的String("123")对象。当程序员使用str=null时,便切断了str与new String(“123”)的引用,因此,new String("123")就失去了强可触及的状态,转而进入可恢复状态。

2. 可恢复。当JVM准备对该对象进行垃圾回收时,它会调用该类的finalize()方法。用户可以重写类的finalize方法(Object类的方法)。finalize()方法相当于是给对象再一次机会获得引用,若获得了引用,则恢复强可触及状态,否则,将进入不可达状态。

3. 不可达状态。当JVM发现一个对象是不可达时,它将回收该对象的内存。

Java引用对象和JVM的垃圾回收器密切相关。Java的引用对象在创建之后便一直维持对该对象的引用,直到该对象没有任何存在价值。Java的引用对象都继承自Reference抽象类,每一种实现都有它自身的独特之处。SoftReference可以用来避免OOM的问题,当系统的内存用尽时,将回收系统中的无用对象(存在时间最久的将被第一个回收)。WeakReference可以用来保护对象避免泄露,当WeakReference对象没有引用时,垃圾回收器将毫不犹豫地清理掉它。PhantomReference对象维持一个很弱的引用,它只是在对象准备回收时将它引用放入ReferenceQueue中,其实对象已经不存在,只是它提供了一种方法来避免finalize方法将它恢复的可能性。

使用SoftReference来构建缓存

创建Student类

public class Student {
    private String id;
    private String name;
    private int classno;
    
    public Student (String id , String name , int classno) {
        this.id = id;
        this.name = name;
        this.classno = classno;
    }
    
    public String getID() {
        return this.id;
    }
    
    public String toString() {
        return this.id+" "+this.name+" "+this.classno;
    }
}

创建SoftReference类的子类,使它符合使用要求(如start的时间,可用于在Map里面清除满足条件的Entry)

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

/**
 *
 * @author Administrator
 */
public class StudentRef extends SoftReference{
    private long start;

    public StudentRef(Student stu, ReferenceQueue q) {
        super(stu, q);
        this.start = System.currentTimeMillis();
        System.out.println(start);
    }
    
    public long getStartTime() {
        return this.start;
    }
}

创建Cache的对象和方法

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class StudentCache {
    private HashMap<String ,StudentRef> map;
    private ReferenceQueue rq;
    static private StudentCache sc;
    
    private StudentCache() {
        rq = new ReferenceQueue();
        map = new HashMap<String,StudentRef>();
    }
    
    public static StudentCache getInstance() {
        if(sc == null) {
            return new StudentCache();
        } else{
            return StudentCache.sc;
        }
    }
    /*如果满足条件的空的Reference,就清除*/
    public void cleanCache() {
        Reference r = null;
        while((r=rq.poll())!=null) {
            r.clear();
        }
    }  
    
    /*将对象加入Map中*/
    public void cacheStudent (Student stu) {
        if(map.containsKey(stu.getID())) {
            return;
        }
        /*将引用注册进ReferenceQueue中,以便管理Reference对象的生存时间*/
        StudentRef sturef = new StudentRef(stu,rq);
        map.put(stu.getID(), sturef);
        System.out.println("cached student "+stu.getID());
    }   

    /*获取缓存中的数据,否则就创建缓存*/
    public Student getStudentFromCache (String id) {
        if(map.containsKey(id)) {
            StudentRef sturef = map.get(id);
            System.out.println("Student find!");
            return (Student)sturef.get();
        } else {
            System.out.println("Fetching Student" + id + "from DB");
            return null;
        }
    }
    
    public void cleanAll () {
        cleanCache();
        map.clear();
        System.gc();
        System.runFinalization();
    }
    
    /*创建map方法的清除条件*/
    public void cleanMap() {
        long end = System.currentTimeMillis();
        Iterator<Map.Entry<String,StudentRef>> it = map.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry<String,StudentRef> entry = it.next();
            StudentRef sturef = entry.getValue();
            String id = entry.getKey();
            if(end - sturef.getStartTime() > 1000) {
                it.remove();
                System.out.println("Remove "+id);
            }
        }
        cleanCache();
    }
    
    public boolean isEmptyMap() {
        return map.isEmpty();
    }
}

当对象进入缓存后,就可以创建维护SoftReference的类,使用线程或定时器来维护。这里使用定时器来维护超时的HashMap。

import java.util.TimerTask;

/**
 *
 * @author Administrator
 */
public class CleanThread extends TimerTask {
    private static StudentCache sc = StudentCache.getInstance();
    
    @Override
    public void run() {
        System.out.println("Timer start!");
        if(sc.isEmptyMap()) {
            System.out.println("Map is Empty");
        } else {
            sc.cleanMap();
        }     
    }   
}

文中很多内容均来自对http://blog.csdn.net/coolwxb/article/details/7939246的理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值