java 引用队列_Java中管理资源的引用队列相关原理解析

当对象改变其可达性状态时,对该对象的引用就可能会被置于引用队列(reference queue)中。这些队列被垃圾回收器用来与我们的代码沟通有关对象可达性变化的情况。这些队列是探测可达性变化的最佳方式,尽管我们也可以通过检查get方法的返回值是不是null来探测对象的可达性变化。

引用对象在构造时可以与特定队列建立关联。Reference的每一个子类都提供了如下形式的构造器:

.public Strength Reference (T referent, ReferenceQueueq):该方法用给定的指称对象创建新的引用对象,并且把该引用对象注册到给定的队列中。弱引用和软引用在垃圾回收器确定它们的指称对象进人它们所表示的特定可达性状态之后,就会被插人到队列中,并且这两种引用在插人队列前都会被清除。虚引用也会在垃圾回收器确定它的指称对象进入虚可达状态之后,被插入到队列中,但是它们不会被清除。一旦引用对象被垃圾回收器插人到队列中,其get方法的返回值就肯定会是null,因此该对象就再也不能复活了。

将引用对象注册到引用队列中并不会创建队列和引用对象之间的引用。如果我们的引用对象本身变成了不可达的,那么它就不能插人队列了。因此我们的应用需要保持对所有引用对象的强引用。

ReferenceQueue类提供了三个用来移除队列中引用的方法:

.public Reference < ? extends下>poll ():用于移除并返回该队列中的下一个引用对象,如果队列为空,则返回null.

.public Referenceremove ()throws InterruptedException:用于移除并返回该队列中的下一个引用对象,该方法会在队列返回可用引用对象之前一直阻塞。

.public Referenceremove (long timeout) throws interrupte-dException:用于移除并返回队列中的下一个引用对象。该方法会在队列返回可用引用对象之前一直阻塞,或者在超出指定超时后结束。如果超出指定超时,则返回null.如果指定超时为0,意味着将无限期地等待。

poll方法使得线程可以查询某个引用是否在队列中,并且在该引用存在于队列中时执行特定的动作。remove方法可以处理更复杂(更少见)的情况,在该方法中有一个专门的线程负责从队列中移除引用,并执行恰当的动作。这些方法的阻塞行为和object.wait中定义的阻塞行为相同。对于特定的引用,我们可以通过其isEnqueued方法来查询它是否在队列中,也可以通过调用其enqueue方法将其强制插入到队列中,但是通常这种插人是由垃圾回收器完成的。

引用队列中的虚引用可以用来确定对象何时可以被回收。我们不可能通过虚引用来访问任何对象,即使该对象通过其他方式是可达的也是如此,因为虚引用的get方法总是返回null,事实上,用虚引用来查找要回收的对象是最安全的方法,因为弱引用和软引用在对象可终结之后会被插人到队列中,而虚引用是在指称对象被终结之后插人到队列中的,即在该对象可以执行某些操作的最后时刻之后插人队列的,所以它是绝对安全的。如果可以的话,应该总是使用虚引用,因为其他引用会存在finalize方法使用可终结对象的可能性。

考虑一个资源管理器的例子,它可以控制外部资源集合的访问。对象可以请求访问某项外部资源,并且直至操作完成才结束访问,在此之后,它们应该将所用资源返回给资源管理器。如果这项资源是共享的,它的使用权就会在多个对象之间传递,甚至可能会在多个线程之间传递,因此我们很难确定哪个对象是这项资源最后的使用者,从而也就很难确定哪段代码将负责返回这项资源。为了处理这种情况,资源管理器可以通过将资源关联到被称为键( key)的特殊对象上,实现这项资源的自动回收。只要键对象是可达的,我们就认为这项资源还在使用中;只要键对象可以被当作垃圾回收,这项资源就会被自动释放。下面的代码是对上述资源的抽象表示:

interface Resource{

void use(Object key, Object…args);

void release();

}

当获得某项资源时,其键对象必须提供给资源管理器。对于交还的Resource实例,只有在它得到了其对应的键时,才可以使用这项资源。这样就可以确保在键被回收之后,它所对应的资源就不能再被使用了,即便表示这项资源的Resource对象本身可能仍然是可达的。请注意,Resource对象并未存储对键对象的强引用,这一点很重要,因为这可以防止键对象变为不可达的,从而造成资源不能收回。Resource的实现可以嵌套在资源管理器中:

private static class ResourceImpl implements Resource{

int keyHash;

boolean needsRelease=false

ResourceImpl(Object key){

keyHash=System.identityHashCode(key);

//=set up the external resource

needsRelease=true; }

public void use(Object key,Object... args){

if (System.identityHashCode(key)!=keyHash)

throw new IlleqalArgumentException("wrong key"

//...use the resource

}

public synchronized void release(){

if (needsRelease){

needsRelease=false:

//=release the resource

}

}

}

在资源被创建时就存储了键对象的散列码,并且无论何时调用use方法,它都会检查是否提供了相同的键。对资源的实际使用可能还需要进行同步,但是为了简单起见,我们在这里把它们省略了。release方法负责释放资源,它可以由资源的使用者在使用结束之后直接调用,也可 以由资源管理器在键对象不再被引用时调用。因为我们将使用独立的线程来监视引用队列,所以release方法必须是synchronized的,并且必须允许多次调用。

实际的资源管理器具有如下形式:

public final class ResourceManager{

final ReferenceQueue

键对象可以是任意对象,与让资源管理器分配键对象相比,这赋予了资源使用者极大的灵活性。在调用getResource方法时,会创建一个新的Resource工mpl对象,同时会把提供给该方法的键传递给这个新的ResourceImpl对象。然后会创建一个虚引用,其指称对象就是传递给该方法的键,之后这个虚引用会被插人到资源管理器的引用队列中。最后所创建的虚引用和引用对象会被存储到映射表中,这个映射表有两个用途:一是保持所有的虚引用对象都是可达的,二是可以提供便捷的方法来查询每个虚引用所关联的实际的Resource对象。(另一种方式是子类化PhantomReference并将Resource对象存在一个字段中。)

如果键对象变成了不可达的,那么资源管理器会使用独立的“收割机”(reaper)线程来处理资源。shutdown方法通过终止收割机线程(以响应中断)从而导致getResource方法抛出Ille-llleStateException异常来“关闭”资源管理器。在这个简单的设计中,任何在资源管理器关闭之后插人队列的引用都不会得到处理。实际的收割机线程如下:

class ReaperThread extends Thread{

public void run(){

//run until interrupted

while (true){

try{

Reference ref=queue.remove();

Resource res=null;

synchronized(ResourceManager.this){

res=refs.get(ref);

refs . remove(ref);

}

res .release();

ref.clear();

}

catch (InterruptedException ex){

break;//all done

}

}

}

}

ReaperThread是内部类,并且给定的收割机线程会一直运行,直至与其相关联的资源管理器关闭。该线程会在remove方法上阻塞,直至与特定键相关联的虚引用被插人到引用队列中为止。这个虚引用可以从映射表中获取对Resource对象的引用,然后这一项“键一引用”对将会从映射表中移除。紧接着,在Resource对象上调用其release方法来释放这项资源。最后,

虚引用被清除,使得键可以被回收。

作为一种替代使用独立线程的方案,凡是在引用队列上调用poll方法并释放其键已经变为不可达的所有资源的操作都可以用getResourc“方法来替代,shutdow”方法也可以用来执行最后的poll操作。而资源管理器的语义将依赖于实际的资源类型和资源使用的模式。

使用引用队列的设计与直接使用终结(特别是使用虚引用)的设计相比,要可靠得多。但是我们要记住,对于引用对象插入到引用队列中的确切时间和位置都是不能确定的,我们也不能确定在应用程序终止的时候,所有可插人的引用是否都匕经插人到了引用队列中。如果我们需要确保所有资源在应用程序终止之前都能够被释放掉,就必须要安装必要的关闭挂钩或者使用由应用程序定义的其他协议来确保实现这一点。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Tomcat 替换项目图标

1.首先制作一个32*32像素的图标&#xff0c;命名为favicon.ico这里名称必须是和Tomcat的webapps下的ROOT下的一样。 2.把制作好的图标放到你要部署的Web项目的images目录下&#xff0c;如果你的Web项目有过滤器等&#xff0c;要给后缀名为.ico的图标放行。 3.最后你就可以在你需…

hp 导出日志 远程管理卡_惠普服务器远程管理卡安装详解

可以远程管理服务器。带惠普基于Web的网络资源管理和性能监视工具HP Toptools惠普远程管理卡的主要功能是可以实现对服务器的远程监控&#xff0c;其中包括察看日志、远程诊断、远程开/关机、重启等等。基于惠普远程管理卡的重要功能&#xff0c;本文将着重介绍惠普远程管理卡的…

java 错误登陆次数_纯java代码实现登陆次数验证,登陆错误5次之后锁定30分钟

本方法因为是根据思路纯手写&#xff0c;代码可以再简化&#xff0c;功能尝试没问题&#xff0c;最主要就是在登陆验证中的逻辑&#xff0c;checkLogin()方法是登录前的验证&#xff0c;而真正的登陆方式采用的是Shiro&#xff0c;若不是采用Shiro登陆&#xff0c;将该逻辑采用…

java 监听器 分类_java过滤器和监听器详解 分类: 学习专区

过滤器1、Filter工作原理(执行流程)当客户端发出Web资源的请求时&#xff0c;Web服务器根据应用程序配置文件设置的过滤规则进行检查&#xff0c;若客户请求满足过滤规则&#xff0c;则对客户请求&#xff0f;响应进行拦截&#xff0c;对请求头和请求数据进行检查或改动&#x…

linux java启动脚本文件_不错的linux下通用的java程序启动脚本

#!/bin/sh#该脚本为Linux下启动java程序的通用脚本。即可以作为开机自启动service脚本被调用&#xff0c;#也可以作为启动java程序的独立脚本来使用。##Author: tudaxia.com, Date: 2011/6/7##警告!!!&#xff1a;该脚本stop部分使用系统kill命令来强制终止指定的java程序进程。…

linux心跳包检测代码_OpenSSL心跳包越界读敏感信息泄漏漏洞

发布日期&#xff1a;2014-04-10CVE ID&#xff1a;CVE-2014-0160受影响的软件及系统&#xff1a;OpenSSL 1.0.1&#xff0d;OpenSSL 1.0.1fOpenSSL 1.0.2-betaOpenSSL 1.0.2-beta1未受影响的软件及系统&#xff1a;OpenSSL 0.9.8OpenSSL 1.0.0OpenSSL 1.0.1gOpenSSL 1.0.2-bet…

mysql数据库主要负责存储_mysql数据库自带数据库介绍

show databases&#xff1b;查看mysql自带数据库有information_schema&#xff0c;mysql&#xff0c; performance_schema&#xff0c; testinformation_schema数据库有40张表&#xff0c;如下。在MySQL中&#xff0c;把 information_schema 看作是一个数据库&#xff0c;确切说…

python 编辑数学公式_Jupyter快速编辑高大上数学公式 泰勒展开式

欢迎点击「算法与编程之美」↑关注我们&#xff01;本文首发于微信公众号&#xff1a;"算法与编程之美"&#xff0c;欢迎关注&#xff0c;及时了解更多此系列博客。人工智能的基础是机器学习&#xff0c;而通过之前的几篇博客了解到&#xff0c;机器学习的基础是数学…

用java写一个日历_使用JAVA写一个简单的日历

JAVA写一个简单的日历import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.util.GregorianCalendar;import java.util.Scanner;/*** 制作一个简单的日历** author 这…

MySQL定时任务event,储存过程(定时删除指定时间前90天指定表的数据)

<span style"font-family: Microsoft YaHei; font-size: 14px;">MySQL定时任务event</span> 由于一些业务需求&#xff0c;我们可能需要定时清除数据库一些废弃的数据&#xff0c;可以使用mysql的存储过程和事件来完成。 下面例子定时清除日志表tbl_base…

python慢为什么用的人还很多_为什么是所有人比python标准慢得多吗?

通过使用生成器理解而不是列表理解&#xff0c;可以使这两个函数更快、更具可比性。在s """import numpy as np;x, y np.random.rand(1000),np.random.rand(1000);(all((x[i], y[i])) for i in range(1000)) """timeit.timeit(s,number1000)0.…

Java规定构造方法和类名相同_不是说:java构造方法和类名一定要相同吗?为什么我看见很多构造方法跟类名不完全一致啊?隐藏了什么吗?...

比如以下代码。类名不是TestCar_EX才对吗&#xff1f;为什么构造方法名却是Car&#xff1f;我看见很多教程都是这么写的。晕。。。。。。。。。。。到底怎么样才是对的啊&#xff1f;public class TestCar_EX {public static void main(String[] args) {Car c1 new Car("…

java pdf stamper_PDFStamper在几个PDF文件上失败(itext 5.5.1)

我尝试使用数据填充PDF表单并获得PDFStamper(itext版本5.5.1)以处理多个PDF文件&#xff0c;但在某些情况下它总是失败。示例代码&#xff1a;PdfReader reader new PdfReader(new FileInputStream("C:/Temp/source.pdf"));PdfStamper stamper new PdfStamper(read…

用猎物皮毛换酒喝java_荒野大镖客2三星毛皮狩猎技巧分享 各种类猎物三星皮毛获取方法...

荒野大镖客2三星毛皮怎么获得&#xff1f;想必很多朋友都还不是很清楚吧&#xff0c;所以呢小编今天给大家带来的就是荒野大镖客2三星毛皮狩猎技巧分享&#xff0c;需要的朋友还不快进来看看&#xff1f;三星毛皮狩猎技巧分享猎物体型分水岭建议以狐狸类为例。(1)中型猎物[比狐…

Java调用WebService接口实现发送手机短信验证码功能,java 手机验证码,WebService接口调用...

近来由于项目需要&#xff0c;需要用到手机短信验证码的功能&#xff0c;其中最主要的是用到了第三方提供的短信平台接口WebService客户端接口&#xff0c;下面我把我在项目中用到的记录一下&#xff0c;以便给大家提供个思路&#xff0c;由于本人的文采有限&#xff0c;还请大…

java中的udp丢包_UDP丢包问题

wxbcrefut&#xff1a;谢谢楼主分享&#xff0c;最近也遇到这种问题&#xff0c;我在虚机里测试(配置为8核16G内存)&#xff0c;1s接受2W条数据丢包就特别严重&#xff0c;我还没有处理只是接受而已&#xff0c;不知道问题出在哪&#xff0c;求指教我是用java写的&#xff0c;代…

java人体识别_用华为HMS ML kit人体骨骼识别技术,Android快速实现人体姿势动作抓拍...

items results.getAnalyseList();// 开发者根据需要处理识别结果&#xff0c;例如&#xff0c;在此方法中进行相似度计算&#xff0c;从而在检测到特定姿势后进行拍照等操作。// 需要注意&#xff0c;这里只对检测结果进行处理&#xff0c;不可调用ML Kit提供的其他检测相关接…

java中select的用法_mybaties中select用法,以及常用增删改查

查询语句是使用 MyBatis 时最常用的元素之一select元素配置细节如下属性描述取值默认id在这个模式下唯一的标识符&#xff0c;可被其它语句引用parameterType传给此语句的参数的完整类名或别名resultType语句返回值类型的整类名或别名。注意&#xff0c;如果是集合&#xff0c;…

jpa java.util.map_使用JPA存储Map String,String

JPA 2.0通过ElementCollection注释可以支持原语集合&#xff0c;您可以将其与java.util.Map集合支持一起使用。这样的事情应该起作用&#xff1a;Entitypublic class Example {Id long id;// ....ElementCollectionMapKeyColumn(name"name")Column(name"value&q…

Js获取短信验证码前段效果

一&#xff1a;先上效果图&#xff1a; 二&#xff1a;源代码文件&#xff1a;reg.html: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http:…