我读到JVM gc在找到无法访问的Object之后运行该对象的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运行,因为“A stuff is finalized”出现在标准输出上,但是main中的printline抛出了IndexOutOfBoundsException。我可以完成这项工作吗?
我通常不会使用finalize,我只是觉得看看finalize是否可以再次使用它的对象引用会很有趣。我可以做这个工作吗?
答案 0 :(得分:2)
终结器在专用的终结器线程中运行,你编写的是线程不安全的代码。例如,使用同步集合。
另一个缺陷是,只是调用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());
}
}
答案 1 :(得分:0)
List<Object> list = new ArrayList<>();
list.add(new Stuff(list));
list.remove(0);
System.gc();
System.out.println(list.get(0));
您正在创建Object
的{{1}}个Lis
类实例列表Stuff
已实施finalize
。所以ArrayIndexOutOfBound
是预料之中的。