Search code examples
javareferenceescapingthisjava.util.concurrent

Why does this code cause "this reference" to escape implicitly?


What does "When the inner EventListener instance is published,so is the enclosing ThisEscape instance." mean?

This quote is from 《java Concurrency in Practice》

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

}


Solution

  • ThisEscape instance is published during construction because doSomething is a method of ThisEscape , which can cause unforeseen problems.

    A simple code example, when a event occurs, the ThisEscape object has not yet been built, but since this ThisEscape is registered with the EventSource, then onSomeThing method is triggered, and an NPE is generated because ThisEscape#data has not yet been initialized:

    public class ThisEscape {
        static class EventSource {
            private List<EventListener> eventListeners = new ArrayList<>();
            public void registerListener(EventListener eventListener) {
                eventListeners.add(eventListener);
            }
            public void eventHappen(Event event) {
                eventListeners.forEach(eventListener -> {
                    eventListener.onEvent(event);
                });
            }
        }
        static class Event {
            public String eventString;
            public Event(String eventString) {
                this.eventString = eventString;
            }
        }
        interface EventListener {
            void onEvent(Event e);
        }
        private List<String> data;
        public void doSomething(Event e) {
            data.add(e.eventString);
        }
        public ThisEscape(EventSource source) {
            source.registerListener(
                    new EventListener() {
                        public void onEvent(Event e) {
                            doSomething(e);
                        }
                    }
            );
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.data = new ArrayList<>();
        }
        public static void main(String[] args) {
            EventSource eventSource = new EventSource();
            new Thread(() -> {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                eventSource.eventHappen(new Event("hello"));
            }).start();
            ThisEscape thisEscape = new ThisEscape(eventSource);
        }
    }