假设此代码:
public class Foo {
public static Thread thread;
public String thing = "Thing!!";
public static void main(String[] args) {
new Foo().makeThread();
// <- Foo object may get garbage collected here.
thread.start();
}
private void makeThread() {
thread = new Thread(new Runnable() {
@Override
public void run() {
// !! What if the instance of Foo is long gone?
System.out.println(thing);
}
});
}
}
此处,临时对象new Foo()
创建一个静态保留的Thread thread
,它在String thing
的匿名实现中使用与实例关联的Runnable
。 String thing
到期后new Foo()
是否会收集垃圾,还是会在run()
内继续使用垃圾?为什么呢?
答案 0 :(得分:11)
匿名内部类将引用Foo
,因为它是如何访问thing
的。就好像你有:
public class FooRunnable implements Runnable {
private final Foo foo;
public FooRunnable(Foo foo) {
this.foo = foo;
}
public void run() {
System.out.println(foo.thing);
}
}
然后:
private void makeThread() {
thread = new Thread(new FooRunnable(this));
}
基本上,当新线程使Runnable
实现的实例保持活动状态时,这反过来会阻止Foo
实例被垃圾回收。
答案 1 :(得分:10)
在将thread
设置为null
或其他Thread
之前,不会对字符串进行垃圾回收,因为有一系列引用从静态变量导向对象
参考链如下所示:
static thread
隐式引用Foo
的实例,通过从Runnable
派生的匿名类实例创建它。反过来,Foo
的实例保存对thing
的引用,确保对象不会被垃圾收集。
如果Foo的实例早已不复存在怎么办?
Foo
不会去任何地方,因为它会通过Thread
对象的隐式引用保持实时。
注意:此答案故意忽略了从字符串文字创建的实际String
对象的影响。