Java ~ Reference ~ ReferenceQueue【总结】

前言


 文章

  • 相关系列:《Java ~ Reference【目录】》(持续更新)
  • 相关系列:《Java ~ Reference ~ ReferenceQueue【源码】》(学习过程/多有漏误/仅作参考/不再更新)
  • 相关系列:《Java ~ Reference ~ ReferenceQueue【总结】》(学习总结/最新最准/持续更新)
  • 相关系列:《Java ~ Reference ~ ReferenceQueue【问题】》(学习解答/持续更新)
  • 涉及内容:《Java ~ Reference【总结】》
  • 涉及内容:《Java ~ Reference ~ FinalReference【总结】》

一 概述


 简介

    ReferenceQueue(引用队列)类是Reference(引用)框架中专门设计用来与Reference(引用)抽象类配合使用的队列,采用链表的方式以实现。其作用是追踪引用的所指对象的GC状态,即判断所指对象是否已/会被GC回收。如果一个引用注册了引用队列,并且其所指对象被GC判定为可回收,则该引用会被加入到注册引用队列中(实际上这里只是简单叙述,将引用加入注册引用队列中其实是有相关运行流程的,这个运行流程被称为Reference(引用)机制,该知识点会在讲解引用抽象类的文章中详述)。这就意味着引用队列中的引用的所指对象必然已/会被GC回收,因此加入注册引用队列的引用可作为其所指对象已被GC回收的判断依据,开发者可以通过从注册引用队列中获取引用的方式来判断其对应的所指对象是否已/会被GC回收,并以此为契机执行某些自定义操作,例如回收堆外内存等。

    引用队列类的是无界队列,即容量理论上只受限于内容大小。

    引用队列类的本质是堆栈。虽然命名为队列,但引用队列的插入/移除操作都会在头部发生,因此引用队列类的本质是堆栈而非队列,这也就意味着引用的移除是非公平的,即后插入的引用反而会被先移除。

    引用队列类是线程安全的。引用队列类被用于多线程环境中,会被一条“引用处理器”线程及未知数量的用户线程共同访问,因此为了避免数据安全问题,其必须保证线程安全。引用队列类采用“单锁”线程安全机制,通过synchronized关键字来负责加锁,锁对象是其内部自实现的静态Null类对象…感觉完全没必要啊…用this不就可以了…

    引用队列类并不是Collection(集)框架的成员。虽说名为队列,但引用队列类并没有实现/继承Queue(队列)接口或集框架范围内的其它接口/抽象类/类,因此引用队列类并不是集框架的成员,是完全由引用框架自实现的。

 结构

在这里插入图片描述

二 使用


 创建

  • public ReferenceQueue() —— 创建引用队列。

 方法

  • public Reference<? extends T> poll() —— 轮询 —— 从当前引用队列的头部移除并获取引用。该方法是移除方法中“特殊值”形式的实现,当引用队列中存在引用时移除并返回头引用;否则返回null。

  • public Reference<? extends T> remove() throws InterruptedException —— 移除 —— 从当前引用队列的头部移除并获取引用。该方法是移除方法中“阻塞”形式的实现,当引用队列中存在引用时移除并返回头引用;否则等待至存在引用。该方法直接调用“超时”形式的移除方法实现,其传入的超时参数为0,表示无限等待。

  • public Reference<? extends T> remove(long timeout) throws IllegalArgumentException, InterruptedException —— 移除 —— 从当前引用队列的头部移除并获取引用。该方法是移除方法中“超时”形式的实现,当引用队列存在元素时移除并返回头引用;否则在指定等待时间内等待至存在引用,超出指定等待时间则返回null。当超时参数传0时表示无限等待。

    上述列举了引用队列类关于移除的所有方法,如果熟悉Queue(队列)/BlockingQueue(阻塞队列)接口定义的话会发现引用队列类在方法命名上与标准还是有所差异的(例如“阻塞”形式的实现在标准中被命名为take)。具体原因上文也已经提及,是因为引用队列类完全由引用架自实现,不是集框架成员的缘故。

    虽说已经列举了所有的移除方法,但我们似乎还遗漏了些什么…是的,我们没有列举插入方法。是因为没有吗?当然不可能,引用队列类是存在插入方法的,只是该方法并非公共方法,用户线程无法直接访问,理论上只有引用机制的“引用处理器”线程才会通过同包下的引用抽象类来调用该方法。具体如下:

  • boolean enqueue(Reference<? extends T> r) —— 入队 —— 从当前引用队列的头部插入指定引用,成功返回true;否则返回false。基于该方法“头插法”的实现方式可知引用队列类不是标准的FIFO实现,其本质是堆栈。

 模板

/**
 * 主方法
 *
 * @param args 参数集
 */
public static void main(String[] args) {
    // 创建引用队列。
    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    // 以该引用队列为注册引用队列创建若引用及其所指对象。
    Object o1 = new Object();
    Object o2 = new Object();
    WeakReference<Object> weakReference = new WeakReference<>(o1, referenceQueue);
    PhantomReference<Object> phantomReference = new PhantomReference<>(o2, referenceQueue);
    // 断开程序对所指对象的强引用。
    o1 = null;
    o2 = null;
    // 主线程短暂等待1秒,确保JVM有充足的时间将引用加入引用队列中。
    LockSupport.parkNanos(1000000000);
    // 从引用队列中取出引用,从引用队列中取出的引用意味着其所指对象已/会被GC回收。
    Reference<?> reference;
    while ((reference = referenceQueue.poll()) != null) {
        System.out.println("引用【" + reference + "】的所指对象已/会被GC回收。");
    }
}

三 实现


 “空”引用队列与“入队”引用队列

    “空”引用队列与“入队”引用队列是引用队列类中创建的两个全局静态引用队列,是引用队列类的内部静态子类Null(空)类的对象,我们可以将之视为两个全局引用队列常量,虽然其并没有被修饰final关键字。空类重写了引用队列类的enqueue(Reference<? extends T> r)方法,令之固定返回false,意味着空类对象虽然是引用队列,但却永远都不会有引用入队。相关源码如下:

private static class Null<S> extends ReferenceQueue<S> {
    @Override
    boolean enqueue(Reference<? extends S> r) {
        // 入队操作直接返回false,意味着引用永远都不可能成功入队。
        return false;
    }
}

static ReferenceQueue<Object> NULL = new Null<>();
static ReferenceQueue<Object> ENQUEUED = new Null<>();

    “空”引用队列与“入队”引用队列分别被作为展示引用不同状态的标记值使用。引用存在状态的概念,用于表示其在引用机制中标的不同阶段,具体会在引用抽象类相关文章中详述。在这里我们只需要知道的是:“空”引用队列被作为引用未注册引用队列及引用已从注册引用队列出队的标记值。即当引用被创建时如果没有注册引用队列,则会将“空”引用队列作为默认注册引用队列(已知“空”引用队列是无法入队的)。以及如果引用已从注册引用队列中出队,则其注册引用队列也会被赋值为“空”引用队列。而对于如何区分引用是未注册引用队列还是已从注册引用中出队,则需要搭配引用中的其它条件综合判断,该知识点会在下文及引用抽象类相关文章中详述;而“入队”引用队列的作用则更加直观,被作为引用已加入注册引用队列的标志值,这一点从命名上就可以看出来…当引用于注册引用队列入队后,引用的注册引用队列会被赋值为“入队”引用队列。

 自引用

    引用队列会将尾引用/节点设置为自引用,即将尾引用/节点自身作为自身在引用队列中的后继引用/节点。尾节点在链表中的后继引用通常都为null,null本身既可以作为标记值也有助于GC。但有时如果基于流程的原因如果null已被作为其它情况的标记值,则自引用也是一种不错的替代方案。自引用不但可以作为标记值,并且在辅助GC中也有着不错的表现(虽然肯定是比不上null的)。

    引用队列之所以会将尾引用/节点设置为自引用与引用的状态有关。引用的后继引用与注册引用队列一样,都是状态的综合判断条件之一,而“空”引用队列与后继引用为null便是引用未注册引用队列的状态值。因此为了与其它状态值进行区分,引用在引用队列中的后继引用不可为null。

 终引用计数

    当引用队列发现入队/出队的引用为FinalReference(终引用)时,会对之进行计数,即对整个JVM(而不是某个引用队列)中的终引用总数进行递增/减。该操作的具体作用未知。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/27687.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【前端 - CSS】第 9 课 - CSS 初体验

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、CSS 定义 2、基础选择器 3、文字控制属性 4、示例代码 5、总结 1、CSS 定义 层叠样式表&#xff08;Cascading Style …

前端vue地图定位并测算当前定位离目标位置距离

前端vue地图定位并测算当前定位离目标位置距离, 下载完整代码请访问uni-app插件市场地址: https://ext.dcloud.net.cn/plugin?id12974 效果图如下: # #### 使用方法 使用方法 <!-- // 腾讯地图key注册地址&#xff08;针对H5端&#xff0c;manifest.json中web配置&…

触发器和事件自动化的讲解

触发器和事件自动化 一、触发器 1、触发器的基本概念 触发器是和表相关的一种数据库对象&#xff0c;可以将他看作一种特殊的存储过程&#xff0c;不需要人为调动的存储过程。 关键字&#xff1a;trigger 基本作用&#xff1a;通过对表进行数据的插入、更新或删除等操作来触…

XGBoost的介绍

一、XGBoost的介绍 1.什么是XGBoost&#xff1f; XGBoost&#xff08;eXtreme Gradient Boosting&#xff09;是一种基于梯度提升树的机器学习算法&#xff0c;它在解决分类和回归问题上表现出色。它是由陈天奇在2014年开发的&#xff0c;如今已成为机器学习领域中最流行和强…

那年我头脑发热,选择了自动化,后来我掉入计算机的世界无法自拔

首先&#xff0c;小雅兰是22届高考考生&#xff0c;而且当时填报志愿也没有填报到计算机相关的专业去&#xff0c;小雅兰是自动化专业的学生&#xff0c;是由于一次偶然的机会&#xff0c;了解到了这个行业&#xff0c;对于写代码所带来的成就感&#xff0c;总之&#xff0c;我…

2023春期末考试选择题R2-9AVL树插入调整详解

题目&#xff1a; 将 8, 9, 7, 2, 3, 5, 6, 4 顺序插入一棵初始为空的AVL树。下列句子中哪句是错的&#xff1f; A. 4 和 6 是兄弟 B. 5 是 8 的父结点 C. 7 是根结点 D. 3 和 8 是兄弟 解题要点&#xff1a; 需要对AVL树的4种旋转方式熟悉。 AVL旋转过程&#xff1a; 根据…

人事管理项目-部门数据删除

人事管理项目-部门数据删除 后端实现前端实现 Spring Boot是一个框架&#xff0c;一种全新的编程规范&#xff0c;它的产生简化了框架的使用&#xff0c;所谓简化是指简化了Spring众多框架中所需的大量且烦琐的配置文件&#xff0c;所以Spring Boot是一个服务于框架的框架&…

使用IDEA使用Git:Git使用指北——实际操作篇

Git使用指北——实际操作 &#x1f916;:使用IDEA Git插件实际工作流程 &#x1f4a1; 本文从实际使用的角度出发&#xff0c;以IDEA Git插件为基座讲述了如果使用IDEA的Git插件来解决实际开发中的协作开发问题。本文从 远程仓库中拉取项目&#xff0c;在本地分支进行开发&…

电路模型和电路定律(3)——“电路分析”

小雅兰期末加油冲冲冲&#xff01;&#xff01;&#xff01; 复习之前的内容&#xff1a; 这样的连接方式是不可以的&#xff1a; 两个电压源&#xff0c;电压值不相同&#xff0c;是不能并联的 两个电流源&#xff0c;电流值不相同&#xff0c;是不能串联的 电流源也不能开…

PoseiSwap的趋势性如何体现?

DEX 代表了一种先进的意识形态&#xff0c;相对于 CEX 其更强调无许可、去中心化以及公开透明。然而随着 DeFi 赛道逐渐从 2021 年年底的高峰逐渐转向低谷&#xff0c;DEX 整体的交易量、TVL等数据指标也开始呈现下滑的趋势&#xff0c;DEX 正在面临发展的新瓶颈期。 在这样的背…

漂亮国因一颗气球而疯狂给质量团队带来的启示

最近漂亮国因为我国的一颗漂洋过海的淘气的民用气球而疯狂。这颗气球成功躲过了号称全球最先进的防空系统&#xff0c;跨越大半个漂亮国&#xff0c;直到被一居民拍照无意间发现&#xff0c;漂亮国才反应过来。多次派战斗机拦截无果&#xff0c;在气球降到15km后&#xff0c;F2…

【云原生】Docker容器服务更新与发现之consul

1.consul的相关知识 1.1 什么是注册与发现 服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的&#xff0c;不保障高可用性&#xff0c;也不考虑服务的压力承载&#xff0c;服务之间调用单纯的通过接口访问。直到后来出现了多个节点的分布式架构&#xff0…

day8 栈顶的种类与应用

目录 多寄存器访问指令与寻址方式 多寄存器内存访问指令 多寄存器内存访问指令的寻址方式 ​编辑 栈的种类与使用 栈的概念 栈的分类 栈的应用举例 叶子函数的调用过程举例 多寄存器访问指令与寻址方式 多寄存器内存访问指令 MOV R1, #1 MOV R2, #2 MOV R3, #3 MOV R…

PL2303HXA自2012已停产,请联系供货商的解决办法

一、概述 PL2303 是Prolific 公司生产的一种高度集成的接口转换器&#xff0c;可提供一个RS232 全双工异步串行通信装置与USB 功能接口便利连接的解决方案。PL2303具有多个历史版本&#xff0c;早期的版本是PL2303HX, 近年有PL2303HXA、PL2303HXC、PL2303HXD&#xff08;D版本…

详解Java中static的使用及其注意事项

1.可以用来修饰的结构&#xff1a; 主要用来修饰类的内部结构 属性、方法、代码块、内部类 2.static修饰属性&#xff1a;静态变量&#xff08;或类变量&#xff09; ​ 2.1 属性&#xff0c;是否使用static修饰&#xff0c;又分为&#xff1a;静态属性 vs 非静态属性(实例…

Java中方法的重载与重写

文章目录 前言方法重载方法重写 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 方法的重载与重写容易混&#xff0c;所以单独拿出来比较 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 方法重载 在同一个类中&#xff0c;允…

注解、原生Spring、SchemaBased三种方式实现AOP【附详细案例】

目录 一、注解配置AOP 1. 开启注解支持 2. 在类和方法加入注解 3. 测试 4. 为一个类下的所有方法统一配置切点 二、原生Spring实现AOP 1. 引入依赖 2. 编写SpringAOP通知类 3. 编写配置类bean2.xml 4 测试 三、SchemaBased实现AOP 1. 配置切面 2. 测试 往期专栏…

【二十七】springboot之通过threadLocal+参数解析器实现同session一样保存当前登录信息的功能

springboot篇章整体栏目&#xff1a; 【一】springboot整合swagger&#xff08;超详细 【二】springboot整合swagger&#xff08;自定义&#xff09;&#xff08;超详细&#xff09; 【三】springboot整合token&#xff08;超详细&#xff09; 【四】springboot整合mybatis…

5.部署LVS-DR群集

文章目录 部署LVS-DR群集LVS-DR数据包流向分析LVS-DR中的ARP问题问题一问题二 LVS-DR部署调度器配置节点服务器配置NFS服务器配置 ipvsadm 部署LVS-DR群集 LVS-DR数据包流向分析 为方便进行原理分析&#xff0c;将Client与群集机器放在同一网络中&#xff0c;数据包流经的路线…

代码随想录第55天

1.判断子序列&#xff1a; 动态规划五部曲分析如下&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度为dp[i][j]。 注意这里是判断s是否…