应该从事件调度程序或主线程控制Swing GUI应用程序吗?

时间:2013-03-13 20:12:19

标签: java multithreading swing event-dispatch-thread invokelater

我读了几本关于Java的书。在所有这些中,至少有一章教授GUI编程。在所有这些中,创建一个简单的表单应用程序遵循以下逻辑:

MyFrame.java

public class MyFrame extends JFrame
{
    JButton button1;

    public MyFrame()
    {
        button1 = new JButton("Click here.");
    }
}

FrameTest.java:

public class FrameTest
{
    public static void main(String[] args)
    {
        MyFrame myFrame = new MyFrame();

        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        myFrame.setSize(600, 600);
        myFrame.setVisible(true);
    }
}

基本上,只需将JFrame子类化为创建表单并将其他组件声明为实例变量,并在构造函数中初始化这些组件。然后创建另一个测试类,在该类中实例化框架子类并调用它的一些方法使其可见。

但在并发课程中,我了解到我们有一个主线程,它在我们创建的每个应用程序中运行main()。据我所知,当我们使用Swing创建GUI应用程序时,我们有另一个线程(Event Dispatcher Thread)。因此,如果我没有记错,在每个基于Swing的GUI应用程序中至少有两个线程。这使得每个GUI应用程序都是多线程的。在我读过的一些文章和教程中,它说Swing不支持多线程,因此只能在Event Dispatcher Thread中创建和修改所有GUI组件,否则可能会出现线程干扰和内存不一致错误。

即使在维基百科(http://en.wikipedia.org/wiki/Swing_%28Java%29)中最简单的例子中,它也是通过invokeLater方法制作的。

那么哪一个是真正的方法?我哪里错了?

2 个答案:

答案 0 :(得分:7)

任何UI / Swing组件的所有交互都必须在EDT的上下文中完成

启动应用程序时,在尝试创建/与任何Swing组件交互之前,应确保在EDT中执行。

简单地说,你应该使用像...这样的东西。

EventQueue.invokeLater(new Runnable() {
    public void run() {
        // Now in the event dispatching thread
    }
});

如果需要运行长时间运行的任务或执行任何阻塞任务,则应在单独的线程中执行它。 SwingWorker在大多数情况下是一个不错的选择,因为它提供了一些简单的机制来将代码重新同步到事件调度线程。

阅读

所以,简短的回答是,是的,所有基于Swing的代码都应该从EDT的上下文中访问/修改/交互

答案 1 :(得分:3)

  

所以如果我没有弄错的话,在每个基于Swing的GUI应用程序中   是至少两个线程

是。一个是主线程,另一个是EDT(事件调度线程)。

  

这使得每个GUI应用程序都成为多线程。

是。但在这种情况下,另一个线程不与GUI组件交互。

  

Swing不支持多线程因此所有GUI组件   应该只在Event Dispatcher Thread中创建和修改   否则线程干扰和内存不一致错误可能会   出现。

是的,绝对正确。这意味着一次只有一个Thread应该与给定的GUI组件交互。
Swing程序员处理以下类型的线程:

  • Initial threads,执行初始应用程序代码的线程。
  • event dispatch thread,执行所有事件处理代码。大多数与Swing框架交互的代码也必须在此线程上执行。
  • Worker threads,也称为后台线程,执行耗时的后台任务。
  

程序员不需要提供明确创建的代码   这些线程:它们由运行时或Swing提供   框架。程序员的工作是利用这些线程来创建   一个响应迅速,可维护的Swing程序。