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


    这篇文章非常棒: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
  • 相关阅读:
    winform中的 listview的使用的讲解。
    快乐的一天从AC开始 | 20210716 | P1345
    快乐的一天从AC开始 | 20210715 | P4643
    快乐的一天从AC开始 | 20210714 | P3594
    快乐的一天从AC开始 | 20210713 | P3557
    快乐的一天从AC开始 | 20210712 | P2251
    P7294-[USACO21JAN]Minimum Cost Paths P【单调栈】
    AT4353-[ARC101D]Robots and Exits【LIS】
    2021牛客暑期多校训练营9C-Cells【LGV引理,范德蒙德行列式】
    Loj#2880-「JOISC 2014 Day3」稻草人【CDQ分治,单调栈,二分】
  • 原文地址:https://www.cnblogs.com/boucher/p/5977943.html
Copyright © 2020-2023  润新知