6

I started reading Java Concurrency in Practice and I came across the following example (this is a negative example - shows bad practice):

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        });
    }
}

The author in the book writes:

When ThisEscape publishes the EventListener, it implicitly publishes the enclosing ThisEscape instance as well, because inner class instances contain a hidden reference to the enclosing instance.

When I think about the usage of such code, I could do something like so:

EventSource eventSource = new EventSource();
ThisEscape thisEscape = new ThisEscape(eventSource);

and I can get the reference to the registered EventListener, but what does it mean that I could obtain the reference to the enclosing ThisEscape instance?

Could someone give me an example of such a behaviour? What is the use case?

agienka
  • 396
  • 1
  • 2
  • 11
  • 1
    Probably this could be an example: https://stackoverflow.com/a/1084124/4563745 – Vasiliy Vlasov Jun 18 '17 at 11:11
  • Ok, this is nice use case, but I still don't understand what is wrong with such escaping reference - even if I'd do ThisEscape.this.doSomething(); from within anonymous implementation, 'this' still stays visible within ThisEscape only. – agienka Jun 18 '17 at 11:26
  • The event source can send events before ThisEscape constructor has finished. The events will be processed with the object in an unpredictable state. – Joni Jun 18 '17 at 11:34
  • Possible duplicate of [Allowing the this reference to escape](https://stackoverflow.com/questions/20474521/allowing-the-this-reference-to-escape) – Joe Jun 18 '17 at 12:03
  • I found another great explanation for the same issue: https://stackoverflow.com/questions/28676796/how-does-this-reference-to-an-outer-class-escape-through-publishing-inner-clas?rq=1 – agienka Jun 18 '17 at 19:40

1 Answers1

1

The problem with escaping this references is that code in other threads might start interacting with the object before the constructor is finished constructing it.

Consider this example:

public class ThisEscape
{
    Foo foo;
    public ThisEscape(EventSource source) {
        source.registerListener(new EventListener()
        {
            public void onEvent(Event e) {
                doSomething(e);
            }
        });

        // Possible Thread Context switch

        // More important initialization
        foo = new Foo();
    }

    public void doSomething(Event e) {
        // Might throw NullPointerException, by being invoked
        // through the EventListener before foo is initialized
        foo.bar();
    }
}
folkol
  • 4,752
  • 22
  • 25