Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will an unreferenced object used in an anonymous class instance not expire?

Assume this code:

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

Here, a temporary object new Foo() creates a statically held Thread thread which utilizes an instance-tied String thing in an anonymous implementation of Runnable. Does the String thing get garbage collected after expiration of new Foo(), or will it persist for its use within run()? Why?

like image 973
Zyl Avatar asked Jul 17 '15 19:07

Zyl


2 Answers

The string will not be garbage-collected until thread is set to null or to some other Thread, because there is a chain of references leading to the object from a static variable.

The chain of references looks like this:

static thread implicitly references the instance of Foo from which it has been created through an instance of anonymous class derived from Runnable. In turn, the instance of Foo holds a reference to thing, making sure that the object does not get garbage collected.

What if the instance of Foo is long gone?

Foo is not going anywhere, because it is kept live by the implicit reference from the Thread object.

Note: This answer intentionally ignores the effect of interning String objects created from string literals.

like image 179
Sergey Kalinichenko Avatar answered Nov 15 '22 04:11

Sergey Kalinichenko


The anonymous inner class will have a reference to the Foo, as that's how it is about to access thing. It's as if you had:

public class FooRunnable implements Runnable {
    private final Foo foo;

    public FooRunnable(Foo foo) {
        this.foo = foo;
    }

    public void run() {
        System.out.println(foo.thing);
    }
}

Then:

private void makeThread() {
    thread = new Thread(new FooRunnable(this));
}

So basically, while the new thread keeps an instance of the Runnable implementation alive, that in turn prevents the instance of Foo from being garbage collected.

like image 26
Jon Skeet Avatar answered Nov 15 '22 06:11

Jon Skeet