When is the Swing UI thread created?

When is the Custom Thread (Event Flow, EDT) first spawned in the process of starting a Swing program? Presumably any JVM could do whatever it wanted (for example, always creating an EDT at startup, regardless of whether or not it was ever used), but how practical is this EDT that is usually created?

Is it thrown when SwingUtilities.invokeLater () is called first? When is the JPanel instantiated first? And if the event pump is triggered separately from the EDT creation, when does it usually happen?

+3


source to share


1 answer


After looking at the code, it appears that it is "lazy initialized", which means initializing it as soon as necessary, if it hasn't already been initialized. In this case, whenever any event is posted to the queue.


Here's the complete story:

EventDispatchThread

concluded in EventQueue

. Everyone EventQueue

has their own EDT:

/**
 * Just a summary of the class
 */
public class EventQueue {
     private static final int ULTIMATE_PRIORITY = 3;
     private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;

     private Queue[] queues = new Queue[NUM_PRIORITIES];
     private EventQueue nextQueue;
     private EventQueue previousQueue;
     private EventDispatchThread dispatchThread;
}

      

dispatchThread

initialized using the private-private method initDispatchThread()

:

final void initDispatchThread() {
    pushPopLock.lock();
    try {
        if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
            dispatchThread = AccessController.doPrivileged(
                new PrivilegedAction<EventDispatchThread>() {
                    public EventDispatchThread run() {
                        EventDispatchThread t =
                            new EventDispatchThread(threadGroup,
                                                    name,
                                                    EventQueue.this);
                        t.setContextClassLoader(classLoader);
                        t.setPriority(Thread.NORM_PRIORITY + 1);
                        t.setDaemon(false);
                        AWTAutoShutdown.getInstance().notifyThreadBusy(t);
                        return t;
                    }
                }
            );
            dispatchThread.start();
        }
    } finally {
        pushPopLock.unlock();
    }
}

      

After checking the references to this method, there are 3 places where this method is called:

  • In a private method EventQueue#wakeup(boolean)

  • In a private method EventQueue#postEventPrivate(AWTEvent)

    (which is called by a public method EventQueue#postEvent(AWTEvent)

    )
  • In a package-private method EventQueue#createSecondaryLoop(Conditional, EventFilter, long)

    .

Before being initDispatchThread()

called is checked dispatchThread

, make sure it hasn't been initialized yet. There are several ways to view all the source code for a class in the JDK (the easiest is to connect the source); learn these methods if you are REALLY interested.

So now we know what the EventQueue

stream contains, and the stream is created whenever we really need it (the event is dispatched). Time to talk about where this queue is located and how they communicate with it.



If you check the code EventQueue#invokeLater(Runnable)

(which is called by its mapping SwingUtilities

), you can see what it calls Toolkit.getEventQueue().postEvent(...)

. This indicates that the queue is in Toolkit

.

Inside the class, Toolkit

we can see that it was created (if not) anytime we call it. It uses reflection to create an object:

public static synchronized Toolkit getDefaultToolkit() {
    if (toolkit == null) {
        try {
            java.lang.Compiler.disable();

            java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                public Void run() {
                    String nm = null;
                    Class<?> cls = null;
                    try {
                        nm = System.getProperty("awt.toolkit");
                        try {
                            cls = Class.forName(nm);
                        } catch (ClassNotFoundException e) {
                            ClassLoader cl = ClassLoader.getSystemClassLoader();
                            if (cl != null) {
                                try {
                                    cls = cl.loadClass(nm);
                                } catch (ClassNotFoundException ee) {
                                    throw new AWTError("Toolkit not found: " + nm);
                                }
                            }
                        }
                        if (cls != null) {
                            toolkit = (Toolkit)cls.newInstance();
                            if (GraphicsEnvironment.isHeadless()) {
                                toolkit = new HeadlessToolkit(toolkit);
                            }
                        }
                    } catch (InstantiationException e) {
                        throw new AWTError("Could not instantiate Toolkit: " + nm);
                    } catch (IllegalAccessException e) {
                        throw new AWTError("Could not access Toolkit: " + nm);
                    }
                    return null;
                }
            });
            loadAssistiveTechnologies();
        } finally {
            // Make sure to always re-enable the JIT.
            java.lang.Compiler.enable();
        }
    }
    return toolkit;
}

      

Toolkit is an abstract class. Instead of instantiating an object of this class, we instantiate a Toolkit: subclass SunToolkit

. We need to know this to see where the queue is being created.

Once we have the Toolkit, we can access the EventQueue with Toolkit#getSystemEventQueue()

. This is a telescope to the protected abstract method getSystemEventQueueImpl()

. We have to check the subclass to see the implementation of this method. In the SunToolkit class, we have:

protected EventQueue getSystemEventQueueImpl() {
    return getSystemEventQueueImplPP();
}

// Package private implementation
static EventQueue getSystemEventQueueImplPP() {
    return getSystemEventQueueImplPP(AppContext.getAppContext());
}

public static EventQueue getSystemEventQueueImplPP(AppContext appContext) {
    EventQueue theEventQueue = (EventQueue) appContext.get(AppContext.EVENT_QUEUE_KEY);
    return theEventQueue;
}

      

(EventQueue) appContext.get(AppContext.EVENT_QUEUE_KEY)

The appContext

toolkit is in line . Now all we need to do is find where the queue is added to the application context:

public SunToolkit() {
    Runnable initEQ = new Runnable() {
        public void run() {
            EventQueue eventQueue;

            String eqName = System.getProperty("AWT.EventQueueClass", "java.awt.EventQueue");

            try {
                eventQueue = (EventQueue) Class.forName(eqName).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
                System.err.println("Failed loading " + eqName + ": " + e);
                eventQueue = new EventQueue();
            }
            AppContext appContext = AppContext.getAppContext();
            appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue); //queue added here

            PostEventQueue postEventQueue = new PostEventQueue(eventQueue);
            appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
        }
    };

    initEQ.run();
}

      

So, a quick overview:

  • EDT is in EventQueue
  • EventQueue is in Toolkit
  • The queue is created when the toolkit is created
  • The toolkit is created either by hand (by calling Toolkit.getDefaultToolkit()

    , or when called by another part of the program (for example, a Swing component that sends data to a queue))
  • EDT is created anytime an event is posted to the queue (and the EDT hasn't been fired yet)

Let me know if you have any questions about this

+9


source







All Articles