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

 更新时间:2015年12月21日 16:20:40   作者:爪哇小博  
这篇文章主要介绍了Java中管理资源的引用队列相关原理解析,涉及到Java的垃圾回收机制方面的知识,需要的朋友可以参考下

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

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

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

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

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

  1.   .public Reference < ? extends下>poll ():用于移除并返回该队列中的下一个引用对象,如果队列为空,则返回null.
  2.   .public Referenceremove ()throws InterruptedException:用于移除并返回该队列中的下一个引用对象,该方法会在队列返回可用引用对象之前一直阻塞。
  3.   .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操作。而资源管理器的语义将依赖于实际的资源类型和资源使用的模式。

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

相关文章

  • idea配置全局变量Jdk、maven仓库以及maven详解(全文图解)

    idea配置全局变量Jdk、maven仓库以及maven详解(全文图解)

    这篇文章主要给大家介绍了关于idea配置全局变量Jdk、maven仓库以及maven的相关资料,在配置JDK和Maven之前,需要确保已经正确安装了JDK和Maven,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • Java更新调度器(update scheduler)的使用详解

    Java更新调度器(update scheduler)的使用详解

    Java更新调度器是Java中的一个特性,可以自动化Java应用程序的更新过程,它提供了一种方便的方式来安排Java应用程序的更新,确保其与最新的功能、错误修复和安全补丁保持同步,本文将深入介绍如何使用Java更新调度器,并解释它对Java开发人员和用户的好处
    2023-11-11
  • logback-spring.xml的内容格式详解

    logback-spring.xml的内容格式详解

    这篇文章主要介绍了logback-spring.xml的内容格式详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的的朋友参考下吧
    2023-11-11
  • Java File类提供的方法与操作

    Java File类提供的方法与操作

    Java使用File类来表示计算机系统磁盘文件的对象类型。File中提供了大量的方法,可以对文件进行增加、删除、修改、重命名等常规操作。File类的对象会存储文件自身的信息,例如文件在系统中的存储目录、文件大小、文件读写权限等
    2023-03-03
  • javaGUI实现多人聊天功能

    javaGUI实现多人聊天功能

    这篇文章主要为大家详细介绍了javaGUI实现多人聊天功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-09-09
  • Java 如何实现照片转化为回忆中的照片

    Java 如何实现照片转化为回忆中的照片

    本文主要介绍了可以对图片进行色彩处理的Java工具类,让图片变成回忆中的画面,主要将图片做黑白与褐色的处理。代码具有一定价值,感兴趣的童鞋可以关注一下
    2021-11-11
  • Java结构型设计模式之装饰模式详解

    Java结构型设计模式之装饰模式详解

    装饰模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能
    2023-03-03
  • 使用Java实现在Excel中创建下拉列表

    使用Java实现在Excel中创建下拉列表

    下拉列表(下拉框)可以确保用户仅从预先给定的选项中进行选择,这样不仅能减少数据输入错误,还能节省时间提高效率,下面我们就来看看如何在java中利用免费库实现创建下拉列表吧
    2024-03-03
  • ReentrantLock源码详解--公平锁、非公平锁

    ReentrantLock源码详解--公平锁、非公平锁

    ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。下面我们来深入了解一下它吧
    2019-06-06
  • 浅谈java分页三个类 PageBean ResponseUtil StringUtil

    浅谈java分页三个类 PageBean ResponseUtil StringUtil

    下面小编就为大家带来一篇浅谈java分页三个类 PageBean ResponseUtil StringUtil。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07

最新评论