Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在哪里调用事件调度线程?_Java_Multithreading_Swing_Event Dispatch Thread - Fatal编程技术网

Java 在哪里调用事件调度线程?

Java 在哪里调用事件调度线程?,java,multithreading,swing,event-dispatch-thread,Java,Multithreading,Swing,Event Dispatch Thread,我读到所有构造Swing组件和处理事件的代码都必须由事件分派线程运行。我理解这是如何通过使用SwingUtilities.invokeLater()方法实现的。考虑下面的代码,其中GUI初始化在主< 方法本身中完成。 public class GridBagLayoutTester extends JPanel implements ActionListener { public GridBagLayoutTester() { setLayout(new GridB

我读到所有构造Swing组件和处理事件的代码都必须由事件分派线程运行。我理解这是如何通过使用
SwingUtilities.invokeLater()
方法实现的。考虑下面的代码,其中GUI初始化在<代码>主< <代码>方法本身

中完成。
public class GridBagLayoutTester extends JPanel implements ActionListener {   
    public GridBagLayoutTester() {
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();

        JButton button = new JButton("Testing");
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        button.addActionListener(this);
        add(button, gbc);
    }

    public void actionPerformed(ActionEvent e) {
        System.out.println("event handler code");
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("GridBagLayoutDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new BorderLayout());
        contentPane.add(new GridBagLayoutTester(), BorderLayout.CENTER);
        frame.setSize(800, 600);
        frame.pack();
        frame.setVisible(true);
        System.out.println("Exiting");
    }   
}
这段代码是如何完美工作的?我们正在构建
JFrame
,并在主线程中调用大量其他方法。我不明白EDT在这里的具体位置(它执行的是什么代码?)。
GridBagLayoutTester
类的构造函数也从
main
方法调用,这意味着EDT没有运行它

总之

  • EDT什么时候开始?(如果在运行此代码时启动了EDT,JVM是否会与main方法一起启动EDT?)
  • 按钮的事件处理程序代码是否在EDT上运行
  • 1) 我不知道是在
    newjframe
    中还是在
    setVisible
    中,但它是按需初始化的,这就是主方法的结尾(通过主进程线程)不会终止进程的原因。EDT已启动,在等待下一个事件的循环中被阻止

    2) 肯定的。该循环从操作系统接收事件,找到JButton并告诉它事件已触发。然后按钮调用侦听器。所有这些都发生在EDT中


    您可以查看在想要终止进程(或关闭主窗口)时调用的Swing代码,以查找EDT终止的位置。。。这可以给你一个线索(我稍后再做):

    事件调度线程,顾名思义,每次需要处理事件时,Swing都会调用它

    在您给出的示例中,“测试”按钮将在需要处理动作事件时自动调用actionPerformed方法。因此,actionPerformed方法的内容将由事件调度线程调用

    回答最后两个问题:

    • 当Swing框架加载时,EDT将自动启动。你不必关心启动这个线程,JRE会为你处理这个任务
    • 事件处理程序代码由EDT运行。Swing接口生成的所有事件都是池化的,EDT负责执行它们

    由于您在EDT有机会与之交互之前在主线程中构建框架,因此代码工作得非常完美。从技术上讲,您永远不应该这样做,但从技术上讲,您可以在这种特定情况下这样做,因为在JFrame变得可见之前,您无法与它交互

    要知道的主要一点是Swing组件不是线程安全的。这意味着不能同时从多个线程修改它们。这可以通过确保所有修改来自EDT来解决

    EDT是一个专门用于用户交互的线程。用户生成的任何事件始终在EDT上运行。EDT上运行的任何用户界面更新。例如,当您调用
    Component.repaint()
    时,您可以从任何线程调用它。这只是设置一个标志,将组件标记为需要绘制,EDT将在下一个周期中进行绘制

    EDT是自动启动的,并且与系统实现紧密相连。它在JVM中处理得很好。通常,它与窗口系统中处理用户交互的单个线程相关。当然,这完全取决于实现。好在你不用担心这个。你只需要知道-如果你与任何Swing组件交互,在EDT上进行

    同样,还有一件事很重要。如果要对外部资源执行任何长时间的处理或阻塞,并且要响应用户生成的事件,则必须将其安排在EDT的自己线程中运行。如果未能执行此操作,将导致用户界面在等待长时间处理运行时阻塞。很好的例子是从文件加载、从数据库读取或与网络交互。您可以使用
    SwingUtilities.isEventDispatchThread()
    方法测试是否在EDT(用于创建可从任何线程调用的中立方法)上

    以下是我在编写处理EDT的Swing编程时经常使用的两段代码:

    void executeOffEDT() { if (SwingUtilities.isEventDispatchThread()) { Runnable r = new Runnable() { @Override public void run() { OutsideClass.this.executeOffEDTInternal(); } }; new Thread(r).start(); } else { this.executeOffEDTInternal(); } } void executeOnEDT() { if (SwingUtilities.isEventDispatchThread()) { this.executeOnEDTInternal(); } else { Runnable r = new Runnable() { @Override public void run() { OutsideClass.this.executeOnEDTInternal(); } }; SwingUtilities.invokeLater(r); } } void executeOffEDT(){ if(SwingUtilities.isEventDispatchThread()){ Runnable r=新的Runnable(){ @凌驾 公开募捐{ OutsideClass.this.executeOffedInternal(); } }; 新线程(r.start(); }否则{ this.executeOffedInternal(); } } void executeOnEDT(){ if(SwingUtilities.isEventDispatchThread()){ this.executeOnEDTInternal(); }否则{ Runnable r=新的Runnable(){ @凌驾 公开募捐{ OutsideClass.this.executeOnEDTInternal(); } }; SwingUtilities.invokeLater(r); } }
    EDT线程在您第一次调用
    setVisible(true)之后启动如果尚未启动,则为ofc。或者如果调用
    SwingUtilities.invokeAndWait()
    SwingUtilities.invokeLater()
    方法


    请参见

    关于Component.repaint(),我怀疑这只是“设置一个标志”,它实际上是对一个绘画事件(然后将由EDT处理)进行排队。模式是相同的。为了成功使用EDT,您不需要知道处理方法的内部结构。因此,frame.setVisible()调用是在EDT上执行的?否。在您的示例中,整个main()方法是在主线程上执行的。EDT上执行的唯一代码行是actionPerformed方法。我看到的标准是创建某种initializeUserInterface()方法,并将其包装