Be crystal clear about
* registration time — could happen hours before
How many threads?
– EDT is the consumer thread
– producer thread
– registration thread? less relevant. can be any thread.
Data shared among these threads at these different TIMES?
+ (singleton) jcomponent object
+ (singleton) action listener object
+ event-queue-task objects.
Before registration time, action listener is instantiated. At registration time, address of the listener object is saved in jcomponent object — like a subscriber mailing list (or spam list:)
At produce-time, system instantiates event-queue-task object (different from EventObject), injecting the jcomponent (as event source) + Listener object addresses therein, then enqueues the task object to the EDT event-queue. If 5 listeners registered, then 5 distinct task objects enqueued.
At consume-time (shortly but possibly much later ), EDT picks up the task object and finds the listener object, and calls listener.actionPerformed() passing in EventObjectt. As a non-static method, this CALL’s host object is the listener object but it executes on EDT. At consume-time, all instance fields of the source object (typically a jcomponent), instance fields of the listener (and, if a nested class within a jcomponent, private fields of the enclosing jcomponent) are accessible.
Listener OBJECT is often of an inner class –> Complicating. You need to be very clear that registration time and listener creation time are rather less relevant since they could be well before the event. Enclosing class’s fields all become accessible to actionPerformed().
If inner class is local, then local variables of the enclosing METHOD are also accessible, if FINAL. This last FINAL scenario is more tricky. The local vars are created at registration time but (because FINAL) remain accessible at consume-time.
 that’s why async always needs buffer — see http://bigblog.tanbin.com/2011/05/asynchronous-always-requires-buffer-and.html