When exactly is the Event Dispatch Thread started?

后端 未结 3 1919
臣服心动
臣服心动 2020-12-17 15:56

When exactly is the EDT started? What line of code is responsible of it?

My guess is that \"someSwingComponent.setVisible(true)\" does the trick, but I\'m not sure.<

相关标签:
3条回答
  • 2020-12-17 16:26

    Q: When exactly is the EDT started? What line of code is responsible [f]of it?

    The inner workings of Swing are JVM-specific. Different JVMs start the Event Dispatch Thread (EDT) based on differing criteria. In general though:

    The EDT starts when it receives its first AWTEvent.

    The stack traces below reaffirm this point. Take for example the following main method.

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setVisible(true);
    }
    

    In the example above, the line of code responsible for starting the EDT is frame.setVisible(true);

    The above main method was executed on two different JVMs. A breakpoint was placed at EventQueue.initDispatchThread. When the breakpoint was hit, the following stack traces were noted.

    Using the Mac's JDK on the AWT-AppKit thread:

    EventQueue.initDispatchThread() line: 906   
    EventQueue.wakeup(boolean) line: 1109   
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39  
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25  
    Method.invoke(Object, Object...) line: 597  
    SunToolkit.wakeupEventQueue(EventQueue, boolean) line: 348  
    PostEventQueue.postEvent(AWTEvent) line: 2137   
    SunToolkit.postEvent(AppContext, AWTEvent) line: 583    
    SunToolkit.executeOnEventHandlerThread(PeerEvent) line: 654 
    SunToolkit.executeOnEventHandlerThread(Object, Runnable) line: 631  
    EventFactoryProxy.windowMoved(CWindow) line: 89 
    

    Using Oracle's JDK for Windows on the main thread:

    java.awt.EventQueue.initDispatchThread() line: 861  
    java.awt.EventQueue.postEventPrivate(java.awt.AWTEvent) line: 199   
    java.awt.EventQueue.postEvent(java.awt.AWTEvent) line: 180  
    javax.swing.RepaintManager.scheduleProcessingRunnable(sun.awt.AppContext) line: 1369    
    javax.swing.RepaintManager.nativeAddDirtyRegion(sun.awt.AppContext, java.awt.Container, int, int, int, int) line: 548   
    javax.swing.SwingPaintEventDispatcher.createPaintEvent(java.awt.Component, int, int, int, int) line: 45 
    sun.awt.windows.WFramePeer(sun.awt.windows.WComponentPeer).postPaintIfNecessary(int, int, int, int) line: 741   
    sun.awt.windows.WFramePeer(sun.awt.windows.WComponentPeer).handlePaint(int, int, int, int) line: 736    
    sun.java2d.d3d.D3DScreenUpdateManager.repaintPeerTarget(sun.awt.windows.WComponentPeer) line: 274   
    sun.java2d.d3d.D3DScreenUpdateManager.createScreenSurface(sun.awt.Win32GraphicsConfig, sun.awt.windows.WComponentPeer, int, boolean) line: 175  
    ...
    sun.awt.windows.WToolkit.createFrame(java.awt.Frame) line: 383  
    javax.swing.JFrame(java.awt.Frame).addNotify() line: 460    
    javax.swing.JFrame(java.awt.Window).show() line: 859    
    javax.swing.JFrame(java.awt.Component).show(boolean) line: 1584 
    javax.swing.JFrame(java.awt.Component).setVisible(boolean) line: 1536   
    javax.swing.JFrame(java.awt.Window).setVisible(boolean) line: 842   
    Example.main(java.lang.String[]) line: 113
    

    On the Mac, a call to PostEventQueue.postEvent(AWTEvent) is made. Similarly on Windows, a call to java.awt.EventQueue.postEvent(java.awt.AWTEvent) is made. Both eventually call EventQueue.initDispatchThread.


    As another example, consider the following main method:

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                System.out.println("Start!");
            }
        });
    }
    

    Using the Mac's JDK on the main thread:

    EventQueue.initDispatchThread() line: 906 [local variables unavailable] 
    EventQueue.postEventPrivate(AWTEvent) line: 227 
    EventQueue.postEvent(AWTEvent) line: 208    
    EventQueue.invokeLater(Runnable) line: 1048 
    SwingUtilities.invokeLater(Runnable) line: 1267 
    Example.main(String[]) line: 31 
    

    Using Oracle's JDK for Windows on the main thread:

    java.awt.EventQueue.initDispatchThread() line: 861  
    java.awt.EventQueue.postEventPrivate(java.awt.AWTEvent) line: 199   
    java.awt.EventQueue.postEvent(java.awt.AWTEvent) line: 180  
    java.awt.EventQueue.invokeLater(java.lang.Runnable) line: 999   
    javax.swing.SwingUtilities.invokeLater(java.lang.Runnable) line: 1267
    

    The call to SwingUtilties.invokeLater is responsible for starting the EDT. Here again, calls to EventQueue.postEvent(AWTEvent) are made.


    Thoughts on 'My guess is that "someSwingComponent.setVisible(true)" does the trick, but I'm not sure.'

    Not just any call to someSwingComponent.setVisible(true) will start the EDT. For example, executing the following main method does not create the AWT-Event-Queue-0 thread:

    public static void main(String[] args) {
        JLabel label = new JLabel();
        label.setVisible(true);
    }
    

    Resources

    Of course, there are many resources online about the EDT.

    • "The Event Dispatch Thread" from The Java Tutorials's "Lesson: Concurrency in Swing"
    • "Threads and Swing" from the Sun Developer Network
    • "Swing Threads" from the Java Glossary at mindprod.com
    • "How does the event dispatch thread work?" on Stack Overflow
    0 讨论(0)
  • 2020-12-17 16:34

    EDIT: You guys are right; The EDT is not started directly on startup. I did some debugging and this is what I found:

    The Event Dispatch Thread is lazly started whenever a component requests access to the event queue by calling Toolkit.getEventQueue(). This can be done when Component.show() is called (the same as Component.setVisible()) but there are also other calls which can trigger this initialization like Component.repaint(). Once a reference to the eventqueue is obtained a job can be added to it with EventQueue.postEvent(). This method checks if the EDT exists and if it doesn't it creates it with initDispatchThread().

    The only way to prevent it from starting is to start the JVM in headless mode (which disables AWT all together) with the "-Djava.awt.headless=true " flag. But thats basically the only low level interaction you can have with it.

    The setVisible method of a Component should always be invoked on the EDT (just like any other modification you make to an Swing / AWT component). You use the EDT by telling Java to execute code on the EDT. The easiest way todo this is to use SwingUtilities.invokeLater(). This schedules your Thread (your Runnable implementation) to be executed from the EDT. This is the only kind of interaction you as a developer should have with the EDT. You shouldn't have any kind of low level interaction with the EDT like pausing or aborting the thread.

    0 讨论(0)
  • 2020-12-17 16:48
    • you are right setVisible for any AWT / Swing container starting EDT, non safe way

    • Initial Thread is about the safest way

    • if all events are done in the present EDT, then isDispatchThread returns false

    • in the case that isDispatchThread returns false, then any Swing thread safe methods could alive the EDT, most safest way is invoke that from invokeLater()

    code for test

    import java.awt.Color;
    import java.awt.EventQueue;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.concurrent.*;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.*;
    
    public class IsThereEDT {
    
        private ScheduledExecutorService scheduler;
        private AccurateScheduledRunnable periodic;
        private ScheduledFuture<?> periodicMonitor;
        private int taskPeriod = 30;
        private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        private Date dateRun;
        private JFrame frame1 = new JFrame("Frame 1");
    
        public IsThereEDT() {
            scheduler = Executors.newSingleThreadScheduledExecutor();
            periodic = new AccurateScheduledRunnable() {
    
                private final int ALLOWED_TARDINESS = 200;
                private int countRun = 0;
                private int countCalled = 0;
                private int maxCalled = 10;
    
                @Override
                public void run() {
                    countCalled++;
                    if (countCalled < maxCalled) {
                        if (countCalled % 3 == 0) {
                            SwingUtilities.invokeLater(new Runnable() {
    
                                @Override
                                public void run() {
                                    System.out.println("Push a new event to EDT");
                                    frame1.getContentPane().setBackground(Color.red);
                                    isThereReallyEDT();
                                }
                            });
                        } else {
                            if (this.getExecutionTime() < ALLOWED_TARDINESS) {
                                countRun++;
                                isThereReallyEDT(); // non on EDT
                            }
                        }
                    } else {
                        System.out.println("Terminating this madness");
                        System.exit(0);
                    }
                }
            };
            periodicMonitor = scheduler.scheduleAtFixedRate(periodic, 0, taskPeriod, TimeUnit.SECONDS);
            periodic.setThreadMonitor(periodicMonitor);
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    isThereReallyEDT();
                    frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame1.getContentPane().add(new JLabel("Hello in frame 1"));
                    frame1.pack();
                    frame1.setLocation(100, 100);
                    frame1.setVisible(true);
                }
            });
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
                Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
            }
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame frame2 = new JFrame("Frame 2");
                    frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame2.getContentPane().add(new JLabel("Hello in frame 2"));
                    frame2.pack();
                    frame2.setLocation(200, 200);
                    frame2.setVisible(true);
                    isThereReallyEDT();
                }
            });
        }
    
        private void isThereReallyEDT() {
            dateRun = new java.util.Date();
            System.out.println("                         Time at : " + sdf.format(dateRun));
            if (EventQueue.isDispatchThread()) {
                System.out.println("EventQueue.isDispatchThread");
            } else {
                System.out.println("There isn't Live EventQueue.isDispatchThread, why any reason for that ");
            }
            if (SwingUtilities.isEventDispatchThread()) {
                System.out.println("SwingUtilities.isEventDispatchThread");
            } else {
                System.out.println("There isn't Live SwingUtilities.isEventDispatchThread, why any reason for that ");
            }
            System.out.println();
        }
    
        public static void main(String[] args) {
            IsThereEDT isdt = new IsThereEDT();
        }
    }
    
    abstract class AccurateScheduledRunnable implements Runnable {
    
        private ScheduledFuture<?> thisThreadsMonitor;
    
        public void setThreadMonitor(ScheduledFuture<?> monitor) {
            this.thisThreadsMonitor = monitor;
        }
    
        protected long getExecutionTime() {
            long delay = -1 * thisThreadsMonitor.getDelay(TimeUnit.MILLISECONDS);
            return delay;
        }
    }
    
    0 讨论(0)
提交回复
热议问题