java.lang.ref.Reference

本文深入解析Java中的引用类型,包括其内部状态、队列操作及处理机制等核心内容。介绍了引用对象的不同状态及其转换,解释了Reference类如何与垃圾回收器协作工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java代码 复制代码  收藏代码
  1. Reference提供了一些引用的基本方法以及静态代码块最高优先级启动ReferenceHandler线程  
Reference提供了一些引用的基本方法以及静态代码块最高优先级启动ReferenceHandler线程
Java代码 复制代码  收藏代码
  1. package xxx;   
  2.     
  3. /**  
  4.  * Abstract base class for reference objects.  This class defines the  
  5.  * operations common to all reference objects. Because reference objects are  
  6.  * implemented in close cooperation with the garbage collector, this class may  
  7.  * not be subclassed directly.  
  8.  * 引用对象的抽象基类。这个类定义了所有引用对象的通用行为。  
  9.  * 因为引用对象是通过与垃圾回收期密切合作来实现的,所以不能直接为此类创建子类.  
  10.  *   
  11.  *  
  12.  * @version  1.43, 04/10/06  
  13.  * @author   Mark Reinhold  
  14.  * @since    1.2  
  15.  */  
  16. public abstract class Reference<T> {   
  17.     /* A Reference instance is in one of four possible internal states:  
  18.      * 一种引用实例是可能是四种内部状态之一:  
  19.      *    Active: Subject to special treatment by the garbage collector.  Some  
  20.      *    time after the collector detects that the reachability of the  
  21.      *    referent has changed to the appropriate state, it changes the  
  22.      *    instance's state to either Pending or Inactive, depending upon  
  23.      *    whether or not the instance was registered with a queue when it was  
  24.      *    created.  In the former case it also adds the instance to the  
  25.      *    pending-Reference list.  Newly-created instances are Active.  
  26.      *    激活:垃圾回收器特别处理的主题。有时候在回收器检测到被引用(对象)的可达性被改变成适当  
  27.      *    的状态,它会把实例的状态改变成等待状态或者未激活状态,这取决于实例是否被一个队列注册当  
  28.      *    它被创建。在前一种情况下(等待状态),它也往等待-引用集合增加实例。  
  29.      *  
  30.      *  
  31.      *    Pending: An element of the pending-Reference list, waiting to be  
  32.      *    enqueued by the Reference-handler thread.  Unregistered instances  
  33.      *    are never in this state.  
  34.      *    等待:一个等待-引用集合里的元素,等待被引用处理线程放入队列中。  
  35.      *    未注册的实例永远不会在这个状态  
  36.      *  
  37.      *    Enqueued: An element of the queue with which the instance was  
  38.      *    registered when it was created.  When an instance is removed from  
  39.      *    its ReferenceQueue, it is made Inactive.  Unregistered instances are  
  40.      *    never in this state.  
  41.      *    入队:实例被创建的时候被登记注册成一个队列的元素。当一个实例从引用队列中删除,它变成非激活状态。  
  42.      *    未注册的实例永远不会在这个状态。        
  43.      *  
  44.      *    Inactive: Nothing more to do.  Once an instance becomes Inactive its  
  45.      *    state will never change again.  
  46.      *    非激活:不会再做什么。一旦一个实例成为非激活的,它的状态永远不会被改变。  
  47.      *      
  48.      *  
  49.      * The state is encoded in the queue and next fields as follows:  
  50.      * 状态在队列里被处理并且每个状态所表现的属性如下:  
  51.      *   
  52.      *  
  53.      *    Active: queue = ReferenceQueue with which instance is registered, or  
  54.      *    ReferenceQueue.NULL if it was not registered with a queue; next =  
  55.      *    null.  
  56.      *    激活:queue=引用队列时候,实例被它注册,  
  57.      *    或者实例不被注册,当queue=ReferenceQueue.NULL时候;  
  58.      *    next=null.  
  59.      *  
  60.      *    Pending: queue = ReferenceQueue with which instance is registered;  
  61.      *    next = Following instance in queue, or this if at end of list.  
  62.      *    等待:queue=引用队列时候,实例被它注册,  
  63.      *    next=剩下的queue队列里面的实例,或者=this,如果this是队列的最后一个。  
  64.      *  
  65.      *    Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance  
  66.      *    in queue, or this if at end of list.  
  67.      *    入队:queue=ReferenceQueue.ENQUEUED   
  68.      *    next=剩下的queue队列里面的实例,或者=this,如果this是队列的最后一个  
  69.      *      
  70.      *      
  71.      *    Inactive: queue = ReferenceQueue.NULL; next = this.  
  72.      *    终止:队列=ReferenceQueue.NULL next=this  
  73.      *  
  74.      * With this scheme the collector need only examine the next field in order  
  75.      * to determine whether a Reference instance requires special treatment: If  
  76.      * the next field is null then the instance is active; if it is non-null,  
  77.      * then the collector should treat the instance normally.  
  78.      *   
  79.      *   
  80.      *   
  81.      * To ensure that concurrent collector can discover active Reference   
  82.      * objects without interfering with application threads that may apply   
  83.      * the enqueue() method to those objects, collectors should link   
  84.      * discovered objects through the discovered field.  
  85.      */  
  86.     private T referent;  /* Treated specially by GC */ //被GC引用的对象   
  87.     ReferenceQueue<? super T> queue;//引用队列   
  88.     Reference next;//下个引用   
  89.     transient private Reference<T> discovered;  /* used by VM *///被VM引用的瞬态对象   
  90.   
  91.     /* Object used to synchronize with the garbage collector.  The collector  
  92.      * must acquire this lock at the beginning of each collection cycle.  It is  
  93.      * therefore critical that any code holding this lock complete as quickly  
  94.      * as possible, allocate no new objects, and avoid calling user code.  
  95.      * GC线程在回收的时候的锁  
  96.      * 对象被用来和GC同步。GC必须获得锁在每个回收的生命周期。  
  97.      * 更关键的是任何持有锁的代码尽可能快的执行完,没有分配新的对象,并避免使用使用者的代码。  
  98.      *   
  99.      */  
  100.     static private class Lock { };   
  101.     private static Lock lock = new Lock();   
  102.   
  103.     /* List of References waiting to be enqueued.  The collector adds  
  104.      * References to this list, while the Reference-handler thread removes  
  105.      * them.  This list is protected by the above lock object.  
  106.      * 排队的引用集合。当处理引用的线程删除引用时候,收集器添加引用到这个集合。  
  107.      * 这个集合受上面的对象锁保护。  
  108.      */  
  109.     private static Reference pending = null;   
  110.     /* High-priority thread to enqueue pending References  
  111.      * 处理排队等待的引用的高优先的线程  
  112.      */  
  113.     private static class ReferenceHandler extends Thread {   
  114.         ReferenceHandler(ThreadGroup g, String name) {   
  115.             super(g, name);   
  116.             }   
  117.         public void run() {   
  118.             for (;;) {   
  119.                 /*  
  120.                  * 给pending赋值  
  121.                  * 如果pending.next=pending,pending=null;否则pending=pengding.next,最后把pending.next=pending  
  122.                  * 下次执行线程里的代码时候pending=null了,再下次执行同步代码块就线程阻塞了  
  123.                  *   
  124.                  * 如果pending属性为空,释放锁的对象监视器,阻塞当前线程  
  125.                  * */    
  126.                 Reference r;   
  127.                 synchronized (lock) {   
  128.                     if (pending != null) {   
  129.                         r = pending;   
  130.                         Reference rn = r.next;   
  131.                         pending = (rn == r) ? null : rn;   
  132.                         r.next = r;   
  133.                     } else {   
  134.                         try {   
  135.                             lock.wait();   
  136.                         } catch (InterruptedException x) { }   
  137.                         continue;   
  138.                     }   
  139.                 }   
  140.                 // Fast path for cleaners    
  141.                 if (r instanceof Cleaner) {   
  142.                     ((Cleaner)r).clean();   
  143.                     continue;   
  144.                 }   
  145.                 /*  
  146.                  *  ReferenceQueue.NULL的实现:   
  147.                  *  private static class Null extends ReferenceQueue {  
  148.                  * boolean enqueue(Reference r) {  
  149.                  * return false;  
  150.             }  
  151.         }  
  152.                  * 如果Q不为空,把引用放入Queue  
  153.                  * 在刚创建一个引用,第二个参数没放Queue时候,为空。  
  154.                  * */  
  155.                 ReferenceQueue q = r.queue;   
  156.                 if (q != ReferenceQueue.NULL) q.enqueue(r);   
  157.             }   
  158.         }   
  159.     }   
  160.         static {   
  161.             //取得当前线程组   
  162.             ThreadGroup tg = Thread.currentThread().getThreadGroup();   
  163.             //取得最上层的System线程组   
  164.             for (ThreadGroup tgn = tg;   
  165.             tgn != null;   
  166.             tg = tgn, tgn = tg.getParent());   
  167.             //创建线程对象   
  168.             Thread handler = new ReferenceHandler(tg, "Reference Handler");   
  169.             /* If there were a special system-only priority greater than  
  170.              * MAX_PRIORITY, it would be used here  
  171.              */  
  172.             handler.setPriority(Thread.MAX_PRIORITY);//设置最高优先级   
  173.             handler.setDaemon(true);//标记守护线程或用户线程   
  174.             handler.start();//守护线程启动   
  175.         }   
  176.   
  177.         /* -- Referent accessor and setters -- */  
  178.         /**  
  179.          * Returns this reference object's referent.  If this reference object has  
  180.          * been cleared, either by the program or by the garbage collector, then  
  181.          * this method returns <code>null</code>.  
  182.          *  
  183.          * @return  The object to which this reference refers, or  
  184.          *   <code>null</code> if this reference object has been cleared  
  185.          * 获得引用对象  
  186.          */  
  187.         public T get() {   
  188.             return this.referent;   
  189.         }   
  190.         /**  
  191.          * Clears this reference object.  Invoking this method will not cause this  
  192.          * object to be enqueued.  
  193.          *  
  194.          * <p> This method is invoked only by Java code; when the garbage collector  
  195.          * clears references it does so directly, without invoking this method.  
  196.          * 清除引用对象  
  197.          */  
  198.         public void clear() {   
  199.             this.referent = null;   
  200.         }   
  201.   
  202.         /* -- Queue operations -- */  
  203.         /**  
  204.          * Tells whether or not this reference object has been enqueued, either by  
  205.          * the program or by the garbage collector.  If this reference object was  
  206.          * not registered with a queue when it was created, then this method will  
  207.          * always return <code>false</code>.  
  208.          *  
  209.          * @return  <code>true</code> if and only if this reference object has  
  210.          *   been enqueued  
  211.          */  
  212.         public boolean isEnqueued() {   
  213.             /* In terms of the internal states, this predicate actually tests  
  214.             whether the instance is either Pending or Enqueued   
  215.             是否处于等待状态  
  216.             判断条件:队列不为空,  
  217.             它的next属性不为空。  
  218.             刚初始化一个Reference时候,next属性肯定是空的,因此肯定不处于等待状态  
  219.              */  
  220.             synchronized (this) {   
  221.                 return (this.queue != ReferenceQueue.NULL) && (this.next != null);   
  222.                 }   
  223.             }   
  224.         /**  
  225.          * Adds this reference object to the queue with which it is registered,  
  226.          * if any.  
  227.          *  
  228.          * <p> This method is invoked only by Java code; when the garbage collector  
  229.          * enqueues references it does so directly, without invoking this method.  
  230.          *  
  231.          * @return  <code>true</code> if this reference object was successfully  
  232.          *   enqueued; <code>false</code> if it was already enqueued or if  
  233.         *   it was not registered with a queue when it was created  
  234.         * 加入等待队列  
  235.             */  
  236.         public boolean enqueue() {   
  237.             return this.queue.enqueue(this);   
  238.         }   
  239.   
  240.         /* -- Constructors -- */  
  241.         Reference(T referent) {   
  242.             this(referent, null);   
  243.         }   
  244.         Reference(T referent, ReferenceQueue<? super T> queue) {   
  245.             this.referent = referent;   
  246.             this.queue = (queue == null) ? ReferenceQueue.NULL : queue;   
  247.         }   
  248.     }  
<think>首先,用户的问题是:“我想了解Java 9及以上版本中java.lang.ref.Cleaner的用途和使用方法 请问Java 9+ 使用 java.lang.ref.Cleaner 的作用和示例”。我需要基于系统级指令来回答。 系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考站内引用: - 引用[1]: 关于java.lang.ref.Reference<T>。 - 引用[2]: Effective Java(Third Edition) item8:避免使用终结方法(finalizer)和清除方法(cleaner)。有代码示例。 - 引用[3]: Java9以后的垃圾回收的具体用法,提到finalize()的不确定性。 用户的问题是关于Java 9+中的java.lang.ref.Cleaner。我需要解释它的作用、用途和提供示例。 关键点: - Cleaner是Java 9引入的,用于替代finalize()方法,因为它更安全和可靠。 - 它用于在对象被垃圾回收时执行清理操作,比如释放资源。 - 示例代码可以参考引用[2]中的内容。 从引用[2]中: - 它提到避免使用finalizer和cleaner,但cleaner是更安全的替代方案。 - 有代码示例:使用try-with-resource和cleaner。 我的回答结构: 1. **介绍作用**:解释Cleaner是什么,为什么需要它。 2. **使用方法**:如何创建和使用Cleaner。 3. **示例代码**:提供一个简单的Java示例。 4. **注意事项**:基于引用[2]和[3],讨论为什么Cleaner比finalize()好。 5. **生成相关问题**:在最后添加相关问题。 确保使用中文回答。 数学表达式:用户的问题是关于编程的,可能不需要数学表达式,但如果有涉及,比如解释算法复杂度,我应该使用$...$。这里可能不涉及,但为了遵守指令,如果有机会,就加入。例如,在解释性能时。 引用标识:在回答中,如果引用参考内容,末尾添加[^1]、[^2]等。例如,基于引用[2]的讨论。 回答结构: - **开头**:简要介绍Cleaner。 - **主体**: - 作用:为什么使用Cleaner。 - 使用方法:步骤和代码。 - 示例:完整的代码示例。 - **结尾**:总结和注意事项。 - **相关问题**:生成3-5个相关问题。 相关问题示例(基于用户问题): 1. Cleaner与finalize()的主要区别是什么? 2. 在哪些场景下应该使用Cleaner? 3. Java 9中Cleaner的实现原理是什么? 4. 如何避免Cleaner的常见陷阱? 现在,构建回答。</think>### Java 9+ 中 java.lang.ref.Cleaner 的作用和使用方法 Java 9 引入了 `java.lang.ref.Cleaner` 类,作为 `finalize()` 方法的替代方案,用于在对象被垃圾回收时执行资源清理操作。`finalize()` 方法存在不确定性(例如,调用时机不可控,可能导致资源泄漏或性能问题),而 `Cleaner` 提供了更安全、可靠的机制[^2][^3]。Cleaner 基于 `java.lang.ref.Reference` 框架实现,通过注册清理动作(如关闭文件或释放内存),在对象不可达时自动触发这些操作,避免手动管理资源的复杂性[^1]。 #### Cleaner 的主要作用 - **资源清理**:自动释放非内存资源(如文件句柄、网络连接),防止资源泄漏。 - **安全性提升**:相比 `finalize()`,Cleaner 的清理动作在单独的守护线程中执行,减少了对主线程的影响,降低了死锁风险。 - **性能优化**:清理动作可预测,不会像 `finalize()` 那样延迟垃圾回收,提高了应用性能[^2][^3]。 - **适用场景**:适用于需要管理本地资源(如通过 JNI 分配的堆外内存)或必须确保资源释放的类(例如数据库连接池)。 #### 使用方法 使用 `Cleaner` 的基本步骤: 1. **创建 Cleaner 实例**:通过 `Cleaner.create()` 获取一个 Cleaner 对象(推荐作为静态实例,避免重复创建)。 2. **注册清理动作**:使用 `register()` 方法将目标对象与一个 `Runnable` 清理任务绑定。当目标对象被垃圾回收时,清理任务会自动执行。 3. **管理 Cleanable 对象**:`register()` 返回一个 `Cleanable` 对象,可通过其 `clean()` 方法手动触发清理(可选)。 4. **注意事项**: - 清理动作应快速执行,避免长时间操作阻塞垃圾回收线程。 - 不要依赖 Cleaner 作为资源管理的唯一方式;优先使用 `try-with-resources` 或显式 `close()` 方法[^2]。 - Cleaner 适用于“安全网”场景,即在显式资源管理失败时提供后备清理。 #### 示例代码 以下是一个简单示例,模拟一个需要清理的资源类(如文件句柄)。代码基于 Java 9+ 语法,并参考了 Effective Java 的最佳实践[^2]。 ```java import java.lang.ref.Cleaner; public class ResourceExample { // 静态 Cleaner 实例,避免重复创建 private static final Cleaner cleaner = Cleaner.create(); // 资源类,代表需要清理的对象(如文件句柄) private static class Resource implements Runnable { private final String resourceId; public Resource(String id) { this.resourceId = id; } @Override public void run() { // 清理动作:释放资源,例如关闭文件或网络连接 System.out.println("Cleaning resource: " + resourceId); } } private final Cleaner.Cleanable cleanable; private final Resource resource; public ResourceExample(String id) { this.resource = new Resource(id); // 注册清理动作:当 ResourceExample 实例被回收时,触发 resource 的 run() 方法 this.cleanable = cleaner.register(this, resource); } // 可选:手动触发清理 public void cleanManually() { cleanable.clean(); } public static void main(String[] args) { // 示例 1: 自动清理(通过垃圾回收触发) new ResourceExample("AutoClean"); System.gc(); // 建议 GC,但不保证立即执行;实际中由 JVM 控制 // 示例 2: 手动清理(显式调用) ResourceExample manualExample = new ResourceExample("ManualClean"); manualExample.cleanManually(); // 示例 3: 使用 try-with-resources 结合 Cleaner(更安全) try (ResourceExample safeExample = new ResourceExample("SafeClean")) { // 使用资源... } // 自动调用 close()(如果实现 AutoCloseable),但 Cleaner 作为后备 } } ``` **代码解释**: - **Resource 类**:实现 `Runnable`,定义清理逻辑(如打印消息模拟资源释放)。 - **注册清理**:在 `ResourceExample` 构造函数中,通过 `cleaner.register(this, resource)` 绑定清理任务。 - **触发方式**: - 自动:当 `ResourceExample` 实例不可达时,垃圾回收器会触发清理(示例中通过 `System.gc()` 模拟)。 - 手动:调用 `cleanManually()` 显式清理。 - **输出示例**: ``` Cleaning resource: ManualClean Cleaning resource: AutoClean (可能延迟输出,取决于 GC 时机) Cleaning resource: SafeClean (如果 try-with-resources 块结束) ``` #### 注意事项 - **为什么优于 finalize()**:`finalize()` 的执行时机不确定,可能导致资源长时间未释放;而 Cleaner 使用守护线程,更轻量且可预测[^3]。 - **性能考虑**:Cleaner 的清理动作不影响对象回收速度,但过多注册可能增加线程负担。建议在关键资源类中使用。 - **最佳实践**:优先结合 `AutoCloseable` 接口和 `try-with-resources`,Cleaner 仅作为额外保障[^2]。例如: ```java public class SafeResource implements AutoCloseable { private final Cleaner.Cleanable cleanable; public SafeResource() { cleanable = cleaner.register(this, () -> System.out.println("Fallback cleanup")); } @Override public void close() { cleanable.clean(); // 显式关闭时触发 } } ``` - **风险**:如果清理动作抛出异常,可能导致线程终止;确保清理代码健壮[^2]。 总之,`java.lang.ref.Cleaner` 是 Java 9+ 中管理资源清理的安全工具,特别适合替代废弃的 `finalize()` 方法。通过注册清理任务,它提供了可靠的“安全网”,但开发者应始终优先使用显式资源管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值