匿名类实例中使用的未引用对象是否会过期?

时间:2015-07-17 19:10:08

标签: java multithreading

假设此代码:

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的匿名实现中使用与实例关联的RunnableString thing到期后new Foo()是否会收集垃圾,还是会在run()内继续使用垃圾?为什么呢?

2 个答案:

答案 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对象的影响。