java - 用Java finalize()弄乱

我读到JVM gc在找到无法访问的对象之后,将运行该对象的finalize()方法。然后,它检查对象是否仍然不可访问,如果不是,则将其清除。所以我写了一个finalize,它将再次使该对象的引用可用:

public class Stuff {

 List<Object> list;

 public Stuff(List<Object> list) {
  this.list = list;
 }

 @Override
 protected void finalize() throws Throwable {
  list.add(this);
  System.out.println("A Stuff is finalized");
 }
}


这是主要方法:

public class Main { 
 public static void main(String[] args) {
  List<Object> list = new ArrayList<>();
  list.add(new Stuff(list));
  list.remove(0);
  System.gc();
  System.out.println(list.get(0));
 }
}


运行gc,因为在标准输出上显示“物料已完成” apperas,但是随后main中的打印行抛出了IndexOutOfBoundsException。我完全可以做这项工作吗?

我通常根本不使用finalize,只是想看看finalize是否可以使其对象的引用再次可用会很有趣。我可以做这个工作吗?

最佳答案

终结器在专用终结器线程中运行,并且您编写的是线程不安全的代码。例如,使用同步的集合。

另一个陷阱是,仅调用System.gc()不能保证在方法调用返回时终结器已经运行。终结器仅已排队在终结器线程的队列中(即使如此)。要解决此问题,您实际上应该使用同步帮助程序(例如CountDownLatch),并调用两次或三遍,以达到良好的效果。

在这里,您的代码通过以上思想得到了改进:

public class Stuff {

  static final List<Stuff> list = Collections.synchronizedList(new ArrayList<Stuff>());
  static final CountDownLatch cdl = new CountDownLatch(1);

  @Override protected void finalize() {
    list.add(this);
    cdl.countDown();
  }

  public static void main(String[] args) throws Exception {
    list.add(new Stuff());
    list.remove(0);
    System.gc();
    System.gc();
    cdl.await();
    System.out.println(list.size());
  }
}

本文翻译自 https://stackoverflow.com/questions/19821213/

网站遵循 CC BY-SA 4.0 协议,转载或引用请注明出处。

标签 java reference finalize


相关文章:

javascript - 对象被复制,但我想要原始的

python - Python-传递对象值而不是引用

c# - Dispose()用于清理托管资源?

java - addParentStack中的NameNotFoundException

java - 如何使用Proguard否定类名

java - 在JTable中对double值进行排序

java - 为什么我的Java对象被复制或finalize()被调用两次?

java - JAXB无法使用非arg构造函数封送和解封Opensaml和Openws对象吗?

c++ - 运营商评估顺序*

c# - 为什么传统的Dispose模式抑制最终完成?