4

Say that (possible on a separate thread) I am running some method ClassA.foobar(). Inside that method is a try, (possibly catch), finally block.

Now if the last reference to this ClassA object (or to this thread) is lost when execution is still in the middle of the try-block (or the catch-block), could this object(/thread) get garbage collected before I get to the finally block? In other words: is the finally block still guaranteed to run even if there are no strong references to the object(/thread) left in memory?

(I don't know how the GC handles orphaned live threads.)

Dummy example:

[Some context]
{
    ClassA classA = new ClassA();
     //Point is this instance and a reference to it exists

    class ClassA
    {
        public void foobar()
        {
            try
            {
                classA = null;
                 //Point is that the last reference to this instance is lost,
                 //and that this happens at this point in foobar() execution.
                 //The actual location of this line of code is irrelevant.
            }
            finally
            {
                //some important stuff here!
            }
        }
    }
}
AnorZaken
  • 1,916
  • 1
  • 22
  • 34
  • 2
    But the last reference is _not_ lost -- `this` still exists and points to that object. And also, the `this` reference is definitely reachable from a GC root (ie, a thread), since it's on a thread's stack frame. In other words, there's no such thing as an "orphaned live thread," since thread itself is what prevents something from being GC'ed (specifically, if a thread knows about the object). So, short is no: the `finally` block is _always_ invoked. – yshavit Nov 04 '13 at 06:43
  • For completeness I wanted to add a link to this comment on a similar question that I found informative: [link](http://stackoverflow.com/questions/65035/does-finally-always-execute-in-java?rq=1#comment4618455_65049) (It makes mention of a depricated case in which the finally block does not run.) – AnorZaken Nov 04 '13 at 06:55
  • That's true, and it's also not run if you invoke `System.exit` or force-kill the Java process (for instance, with `kill -9` on linux). – yshavit Nov 04 '13 at 06:59

1 Answers1

6

In other words: is the finally block still guaranteed to run even if there are no strong references to the object(/thread) left in memory?

Yes. finally blocks don't get skipped like that - nor does any other code.

Execution threads aren't objects in the garbage collection sense. It's important to distinguish between the thread itself and the java.lang.Thread object representing it - although I don't think the Thread object would be garbage collected before the thread terminates either.

In particular, it's entirely possible to have threads where there are no references to the runnable or anything else still in the system, and the thread can keep going. For example:

new Thread(new Runnable() {
    @Override public void run() {
        for (int i = 0; i < 1000; i++) {
             System.out.println(i);
        }
    }
}).start();

After the thread has started, the calling code has no reference to the instance of the anonymous class created, or the Thread object - but it will still print all 1000 numbers.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Which essentially means that it's very much possible to "leak" a thread I presume? I don't suppose there is any way to get back a reference to a thread once you lost it? (Edit: Is code looking like that example considered bad?) – AnorZaken Nov 04 '13 at 07:13
  • @AnorZaken: Not necessarily. "Fire and forget" threads can be useful - you don't *want* to have to look after every thread specifically. Although often using a thread pool (e.g. via an executor service) is a better idea anyway. – Jon Skeet Nov 04 '13 at 07:29
  • The reference to the handle object of the current thread is always available as Thread.currentThread (), which proves that somewhere in the JVM, the reference is retained. – Marko Topolnik Nov 04 '13 at 07:40
  • @MarkoTopolnik: Well, I wouldn't put it past the JVM to work out that there was no possible code path which would still use that... – Jon Skeet Nov 04 '13 at 09:00