这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173

Java中四种引用:强、软、弱、虚引用

1.1、强引用
当我们使用new 这个关键字创建对象时,被创建的对象就是强引用,如Object object = new Object() 这个Object()就是一个强引用。如果一个对象具有强引用,垃圾回收器就不会去回收有强引用的对象,如当jvm内存不足时,具备强引用的对象,虚拟机宁可会报内存空间不足的异常来终止程序,也不会靠垃圾回收器去回收该对象来解决内存。

1.2、软引用

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;

如果内存空间不足了,就会回收这些对象的内存。

只要垃圾回收器没有回收它,该对象就可以被程序使用。

软引用可用来实现内存敏感的高速缓存(下文给出示例)。

软引用可以和一个引用队列(ReferenceQueue)关联使用:

String str = new String("test");
ReferenceQueue<String> rq = new ReferenceQueue<>();
SoftReference sf = new SoftReference(str,rq);

        如果软引用(sf)所引用的对象(str)被垃圾回收器回收,Java虚拟机就会把这个软引用(sf)加入到与之关联的引用队列(rq)中,之后可以通过循环调用rq的poll()方法,来清除无用的软引用对象(sf)

        如果软引用所引用的对象(str)还没有被垃圾回收器回收,则可以通过这个引用(sf)的get()方法重新获得对引用对象(str)的强引用.

 

1.3、弱引用
如果一个对象只具有弱引用,只要垃圾回收器在自己的内存空间中线程检测到了,就会立即被回收,对应内存也会被释放掉。相比软引用弱引用的生命周期要比软引用短很多。不过,如果垃圾回收器是一个优先级很低的线程,也不一定会很快就会释放掉软引用的内存。

通俗的来说就是:发生GC时必定回收弱引用指向的内存空间。

 

示例代码:

public static void main(String[] args) {
	String string = new String("test");
	ReferenceQueue<String> rq = new ReferenceQueue<>();
	WeakReference<String> wr = new WeakReference<String>(string,rq);
	System.out.println(wr.get());
	string = null;
	System.gc();
	System.out.println(wr.get());
}

运行结果:

test
null

 

1.4、虚引用

又称为幽灵引用或幻影引用,虚引用既不会影响对象的生命周期,也无法通过虚引用来获取对象实例,仅用于在发生GC时接收一个系统通知。

相关问题一、若一个对象的引用类型有多个,那到底如何判断它的可达性呢?其实规则如下:

  1. 单条引用链的可达性以最弱的一个引用类型来决定;
  2. 多条引用链的可达性以最强的一个引用类型来决定;

      

     我们假设图2中引用①和③为强引用,⑤为软引用,⑦为弱引用,对于对象5按照这两个判断原则,路径①-⑤取最弱的引用⑤,因此该路径对对象5的引用为软引用。同样,③-⑦为弱引用。在这两条路径之间取最强的引用,于是对象5是一个软可及对象(当将要发生OOM时则会被回收掉)。

 

相关问题二、与引用相关联的引用队列的作用是什么

引用队列的作用:使用ReferenceQueue清除失去了引用对象的Reference(SoftReference,WeakReference等)
作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,如:
ReferenceQueue queue = new ReferenceQueue();
SoftReference ref=new SoftReference(aMyObject, queue);
那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉。常用的方式为:
SoftReference ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
// 清除ref
}
理解了ReferenceQueue的工作机制之后,我们就可以开始构造一个Java对象的高速缓存器了。下面是一个高速缓存器的代码:
EmployeeCache 类:
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Hashtable;

public class EmployeeCache {
	static private EmployeeCache cache;
	private Hashtable<String, EmployeeRef> employeeRefs;
	private ReferenceQueue<Employee> q;
	private class EmployeeRef extends SoftReference<Employee>{
		private String _key="";
		public EmployeeRef(Employee em,ReferenceQueue<Employee> q) {
			super(em,q);
			_key=em.getId();
		}
	}
	private EmployeeCache() {
		employeeRefs = new Hashtable<>();
		q = new ReferenceQueue<>();
	}
	
	public static EmployeeCache getInstance(){
		if(cache==null){
			cache = new EmployeeCache();
		}
		return cache;
	}
	
	private void cacheEmployee(Employee em){
		cleanCache();
		EmployeeRef ref = new EmployeeRef(em, q);
		employeeRefs.put(em.getId(), ref);	
	}
	
	public Employee getEmployee(String id){
		Employee employee = null;
		if(employeeRefs.contains(id)){
			EmployeeRef ref = employeeRefs.get(id);
			employee = ref.get();
		}
		
		if(employee == null){
			employee = new Employee(id);
			System.out.println("从信息中心获取新的对象");
			this.cacheEmployee(employee);
		}
		return employee;
	}
	private void cleanCache() {
		EmployeeRef ref = null;
		while((ref=(EmployeeRef) q.poll())!=null){
			employeeRefs.remove(ref._key);
		}
	}
	public void clearCache(){
		cleanCache();
		employeeRefs.clear();
		System.gc();
		System.runFinalization();
	}
}

Employee类:

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

public class Employee {
	private String id;
	private String name;
	private String department;
	private String phone;
	private int salary;
	private String origin;

	public Employee(String id) {
		this.id = id;
		getDataFromInfoCenter();
	}

	private void getDataFromInfoCenter() {

	}

	public String getId() {
		String id = (int) (Math.random() * 10 + 1) + "";
		return id;
	}
}
 

2、jdk中的引用实现类

代表软引用的类:java.lang.ref.SoftReference
代表弱引用的类:java.lang.ref.WeakReference
代表虚引用的类:java.lang.ref.PhantomReference
他们同时继承了:java.lang.ref.Reference
引用队列:java.lang.ref.ReferenceQueue,这个引用队列是可以三种引用类型联合使用的,以便跟踪java虚拟机回收所引用对象的活动。

 

 

附:相关源码

  1 /*
  2  * @(#)ReferenceQueue.java    1.23 03/12/19
  3  *
  4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6  */
  7 
  8 package java.lang.ref;
  9 
 10 /**
 11  * Reference queues, to which registered reference objects are appended by the
 12  * garbage collector after the appropriate reachability changes are detected.
 13  *
 14  * @version  1.23, 12/19/03
 15  * @author   Mark Reinhold
 16  * @since    1.2
 17  */
 18 
 19 public class ReferenceQueue<T> {
 20 
 21     /**
 22      * Constructs a new reference-object queue.
 23      */
 24     public ReferenceQueue() { }
 25 
 26     private static class Null extends ReferenceQueue {
 27     boolean enqueue(Reference r) {
 28         return false;
 29     }
 30     }
 31 
 32     static ReferenceQueue NULL = new Null();
 33     static ReferenceQueue ENQUEUED = new Null();
 34 
 35     static private class Lock { };
 36     private Lock lock = new Lock();
 37     private Reference<? extends T> head = null;
 38     private long queueLength = 0;
 39 
 40     boolean enqueue(Reference<? extends T> r) {    /* Called only by Reference class */
 41     synchronized (r) {
 42         if (r.queue == ENQUEUED) return false;
 43         synchronized (lock) {
 44         r.queue = ENQUEUED;
 45         r.next = (head == null) ? r : head;
 46         head = r;
 47         queueLength++;
 48                 if (r instanceof FinalReference) {
 49                     sun.misc.VM.addFinalRefCount(1);
 50                 }
 51         lock.notifyAll();
 52         return true;
 53         }
 54     }
 55     }
 56 
 57     private Reference<? extends T> reallyPoll() {    /* Must hold lock */
 58     if (head != null) {
 59         Reference<? extends T> r = head;
 60         head = (r.next == r) ? null : r.next;
 61         r.queue = NULL;
 62         r.next = r;
 63         queueLength--;
 64             if (r instanceof FinalReference) {
 65                 sun.misc.VM.addFinalRefCount(-1);
 66             }
 67         return r;
 68     }
 69     return null;
 70     }
 71 
 72     /**
 73      * Polls this queue to see if a reference object is available.  If one is
 74      * available without further delay then it is removed from the queue and
 75      * returned.  Otherwise this method immediately returns <tt>null</tt>.
 76      *
 77      * @return  A reference object, if one was immediately available,
 78      *          otherwise <code>null</code>
 79      */
 80     public Reference<? extends T> poll() {
 81     synchronized (lock) {
 82         return reallyPoll();
 83     }
 84     }
 85 
 86     /**
 87      * Removes the next reference object in this queue, blocking until either
 88      * one becomes available or the given timeout period expires.
 89      *
 90      * <p> This method does not offer real-time guarantees: It schedules the
 91      * timeout as if by invoking the {@link Object#wait(long)} method.
 92      *
 93      * @param  timeout  If positive, block for up <code>timeout</code>
 94      *                  milliseconds while waiting for a reference to be
 95      *                  added to this queue.  If zero, block indefinitely.
 96      *
 97      * @return  A reference object, if one was available within the specified
 98      *          timeout period, otherwise <code>null</code>
 99      *
100      * @throws  IllegalArgumentException
101      *          If the value of the timeout argument is negative
102      *
103      * @throws  InterruptedException
104      *          If the timeout wait is interrupted
105      */
106     public Reference<? extends T> remove(long timeout)
107     throws IllegalArgumentException, InterruptedException
108     {
109     if (timeout < 0) {
110         throw new IllegalArgumentException("Negative timeout value");
111     }
112     synchronized (lock) {
113         Reference<? extends T> r = reallyPoll();
114         if (r != null) return r;
115         for (;;) {
116         lock.wait(timeout);
117         r = reallyPoll();
118         if (r != null) return r;
119         if (timeout != 0) return null;
120         }
121     }
122     }
123 
124     /**
125      * Removes the next reference object in this queue, blocking until one
126      * becomes available.
127      *
128      * @return A reference object, blocking until one becomes available
129      * @throws  InterruptedException  If the wait is interrupted
130      */
131     public Reference<? extends T> remove() throws InterruptedException {
132     return remove(0);
133     }
134 
135 }
ReferenceQueue
 1 /*
 2  * @(#)SoftReference.java    1.34 03/12/19
 3  *
 4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 6  */
 7 
 8 package java.lang.ref;
 9 
10 
11 /**
12  * Soft reference objects, which are cleared at the discretion of the garbage
13  * collector in response to memory demand.  Soft references are most often used
14  * to implement memory-sensitive caches.
15  *
16  * <p> Suppose that the garbage collector determines at a certain point in time
17  * that an object is <a href="package-summary.html#reachability">softly
18  * reachable</a>.  At that time it may choose to clear atomically all soft
19  * references to that object and all soft references to any other
20  * softly-reachable objects from which that object is reachable through a chain
21  * of strong references.  At the same time or at some later time it will
22  * enqueue those newly-cleared soft references that are registered with
23  * reference queues.
24  *
25  * <p> All soft references to softly-reachable objects are guaranteed to have
26  * been cleared before the virtual machine throws an
27  * <code>OutOfMemoryError</code>.  Otherwise no constraints are placed upon the
28  * time at which a soft reference will be cleared or the order in which a set
29  * of such references to different objects will be cleared.  Virtual machine
30  * implementations are, however, encouraged to bias against clearing
31  * recently-created or recently-used soft references.
32  *
33  * <p> Direct instances of this class may be used to implement simple caches;
34  * this class or derived subclasses may also be used in larger data structures
35  * to implement more sophisticated caches.  As long as the referent of a soft
36  * reference is strongly reachable, that is, is actually in use, the soft
37  * reference will not be cleared.  Thus a sophisticated cache can, for example,
38  * prevent its most recently used entries from being discarded by keeping
39  * strong referents to those entries, leaving the remaining entries to be
40  * discarded at the discretion of the garbage collector.
41  *
42  * @version  1.34, 12/19/03
43  * @author   Mark Reinhold
44  * @since    1.2
45  */
46 
47 public class SoftReference<T> extends Reference<T> {
48 
49     /* Timestamp clock, updated by the garbage collector
50      */
51     static private long clock;
52 
53     /* Timestamp updated by each invocation of the get method.  The VM may use
54      * this field when selecting soft references to be cleared, but it is not
55      * required to do so.
56      */
57     private long timestamp;
58 
59     /**
60      * Creates a new soft reference that refers to the given object.  The new
61      * reference is not registered with any queue.
62      *
63      * @param referent object the new soft reference will refer to
64      */
65     public SoftReference(T referent) {
66     super(referent);
67     this.timestamp = clock;
68     }
69 
70     /**
71      * Creates a new soft reference that refers to the given object and is
72      * registered with the given queue.
73      *
74      * @param referent object the new soft reference will refer to
75      * @param q the queue with which the reference is to be registered,
76      *          or <tt>null</tt> if registration is not required
77      *
78      */
79     public SoftReference(T referent, ReferenceQueue<? super T> q) {
80     super(referent, q);
81     this.timestamp = clock;
82     }
83 
84     /**
85      * Returns this reference object's referent.  If this reference object has
86      * been cleared, either by the program or by the garbage collector, then
87      * this method returns <code>null</code>.
88      *
89      * @return   The object to which this reference refers, or
90      *           <code>null</code> if this reference object has been cleared
91      */
92     public T get() {
93     T o = super.get();
94     if (o != null) this.timestamp = clock;
95     return o;
96     }
97 
98 }
SoftReference