Когда именно начинается Event Dispatch Thread?

Когда именно начинается EDT? Какая строка кода отвечает за это?

Я предполагаю, что "someSwingComponent.setVisible(true)" делает трюк, но я не уверен.

Спасибо!

Ответ 1

Q: Когда именно начинается EDT? Какая строка кода отвечает [f] этого?

Внутренняя работа Swing является специфичной для JVM. Различные JVM запускают Event Dispatch Thread (EDT) на основе разных критериев. В общем, хотя:

EDT начинается, когда он получает свой первый AWTEvent.

Следы стека ниже подтверждают эту точку. Возьмем, например, следующий метод main.

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

В приведенном выше примере строка кода, ответственного за запуск EDT, составляет frame.setVisible(true);

Вышеупомянутый метод main был выполнен на двух разных JVM. Точка останова была помещена в EventQueue.initDispatchThread. Когда была удалена точка останова, были отмечены следующие следы стека.

Использование Mac JDK в потоке AWT-AppKit:

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 

Использование Oracle JDK для Windows в потоке main:

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

На Mac выполняется вызов PostEventQueue.postEvent(AWTEvent). Аналогично в Windows выполняется вызов java.awt.EventQueue.postEvent(java.awt.AWTEvent). Оба они в конечном итоге назовут EventQueue.initDispatchThread.


В качестве другого примера рассмотрим следующий метод main:

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

Использование Mac JDK в потоке main:

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 

Использование Oracle JDK для Windows в потоке main:

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

Ответ на SwingUtilties.invokeLater отвечает за запуск EDT. Здесь также вызываются вызовы EventQueue.postEvent(AWTEvent).


Мысли о "Мое предположение:" someSwingComponent.setVisible(true) "делает трюк, но я не уверен".

Не только любой вызов someSwingComponent.setVisible(true) запустит EDT. Например, выполнение следующего метода main не создает поток AWT-Event-Queue-0:

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

Ресурсы

Конечно, в EDT есть много ресурсов в Интернете.

Ответ 2

EDIT: Ребята, вы правы; EDT не запускается непосредственно при запуске. Я сделал некоторую отладку, и вот что я нашел:

Событие Dispatch Thread запускается всякий раз, когда компонент запрашивает доступ к очереди событий, вызывая Toolkit.getEventQueue(). Это можно сделать, когда вызывается Component.show() (то же самое, что и Component.setVisible()), но есть и другие вызовы, которые могут инициировать эту инициализацию, например Component.repaint(). После получения ссылки на eventqueue задание может быть добавлено к нему с помощью EventQueue.postEvent(). Этот метод проверяет, существует ли EDT, а если нет, он создает его с помощью initDispatchThread().

Единственный способ предотвратить его запуск - запустить JVM в безголовом режиме (который отключает AWT вместе) с флагом "-Djava.awt.headless = true". Но это в основном единственное взаимодействие с низким уровнем, которое вы можете иметь с ним.

Метод setVisible компонента всегда должен вызываться в EDT (как и любая другая модификация, которую вы делаете для компонента Swing/AWT). Вы используете EDT, говоря Java для выполнения кода в EDT. Самый простой способ сделать это - использовать SwingUtilities.invokeLater(). Это запланирует выполнение Thread (ваша реализация Runnable) из EDT. Это единственный вид взаимодействия, который вы, как разработчик, должен иметь с EDT. Вы не должны иметь какое-либо взаимодействие на низком уровне с EDT, например, приостанавливать или прерывать поток.

Ответ 3

  • вы правы setVisible для любого контейнера AWT/Swing, запускающего EDT, безопасный путь

  • Начальный поток - это самый безопасный способ

  • если все события выполняются в настоящем EDT, тогда isDispatchThread возвращает false

  • в случае, когда isDispatchThread возвращает false, тогда любые безопасные методы Swing thread могли бы жить EDT, самым безопасным способом является вызов из invokeLater()

код для тестирования

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;
    }
}