java - 搞乱 java Finalize()

标签 java reference finalize

我读到,JVM gc 在找到无法访问的对象后,会运行该对象的 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 已运行,因为“A stuff is Finalized”出现在标准输出上,但 main 中的打印行随后抛出 IndexOutOfBoundsException。我可以完成这项工作吗?

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

最佳答案

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

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

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

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());
  }
}

关于java - 搞乱 java Finalize(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19821213/

相关文章:

java - 在 StringTokenizer 中有条件地添加字符串

php - 更改函数 php 内的全局变量引用

C++:通过函数修改数组

仅扩展对象的类中的 Java GC : does it ever make sense to call super. finalize()?

Java Finalizer 方法和 GC

java - 编译程序后如何从源文件夹中获取 jar?

java - 如何用java模拟真实的鼠标点击?

java - RESTEasy 多文件上传

java - 如何将一个对象传递给一个类,以便当对象在类外更新时,它在类内也会过时? ( java )

java - 为什么 java.lang.Object 中的 Finalize() 方法是 "protected"?