什么是事件调度线程?

我知道“线程”意味着什么,如果我将事件调度线程(EDT)理解为“只是一个线程”,它解释了很多,但显然,它并没有解释所有内容。

我不明白这个post有什么特别之处。 例如,我不明白为什么我们应该在EDT中启动GUI? 为什么“主”线程适合GUI? 好吧,如果我们只是不想占用主线程为什么我们不能在“另一个线程”中启动GUI为什么它应该是一些称为EDT的“特殊”线程?

然后我不明白为什么我们不能像任何其他线程一样启动EDT? 为什么我们应该使用一些特殊工具(称为invokeLater )。 而且,与其他任何线程不同,GUI不能立即启动。 我们应该等到它准备接受我们的工作。 是因为EDT可以同时执行多项任务吗?

如果你决定回答这个问题,你是否可以使用一个非常简单的术语,否则,我恐怕不会理解答案。

添加:

我一直以为每个post都有一个“任务”。 因此,在每个线程中,我们执行预定义的命令序列。 但在我看来,在事件调度线程中我们可以拥有服务器任务。 好吧,它们不是同时执行的(线程在不同的任务之间切换,但在一个线程中仍然有几个任务)。 这样对吗? 例如,EDT中有一个显示主窗口的线程,然后另外我们向EDT发送另一个应该更新其中一个窗口组件的任务,EDT将在它准备就绪时执行这个新任务。 EDT是否与其他线程不同?

事件调度线程是处理所有GUI事件并管理Swing GUI的线程。 如果您的程序中有任何GUI,它将在Swing代码中的某个位置启动。 它在幕后完成的原因是因为简单 – 您不必费心自己启动和管理额外的线程。

关于必须使用invokeLater()更新GUI的事实,这是因为并发问题。 GUI只能从一个线程修改,因为Swing不是线程安全的(值得注意的是, 大多数工具包都不是线程安全的,有一篇很好的文章提供了一些想法)。 这就是为什么你必须提交所有GUI更新才能在EDT上运行的原因。

您可以在Swing中的并发性和事件调度线程中阅读有关Swing中并发性的Sun教程中的更多信息 。 此外,如果您想了解如何以不同的方式完成此操作,您可能需要查看SWT工具包 。 在SWT中,您必须自己管理EDT。

我一直以为每个post都有一个“任务”。 因此,在每个线程中,我们执行预定义的命令序列。 但在我看来,在事件调度线程中我们可以拥有服务器任务。 好吧,它们不是同时执行的(线程在不同的任务之间切换,但在一个线程中仍然有几个任务)。 这样对吗? 例如,EDT中有一个显示主窗口的线程,然后另外我们向EDT发送另一个应该更新其中一个窗口组件的任务,EDT将在它准备就绪时执行这个新任务。 EDT是否与其他线程不同?

不,EDT与其他线程没有根本的区别。 并且“任务”不是一个好用的词,因为它可能与OS级进程(通常也称为任务)混淆。 最好使用Runnable ,这个接口用于通过invokeLater()为EDT提供代码。

EDT基本上连接到它必须做的事情的队列。 当用户单击GUI上的按钮时,通知连接到该按钮的所有侦听器的Runnable将进入队列。 调整窗口大小时,执行重新validation和重新绘制的Runnable将进入队列。 当你使用invokeLater() ,你的Runnable进入队列。

EDT只是运行一个无限循环,说“从队列中取出一个Runnable (如果它是空的睡眠,直到你被告知它不是)并执行它。

因此,它一个接一个地执行所有那些小的Runnable代码,因此它们中的每一个在运行时基本上都具有GUI,并且不必担心同步任何东西。 当您从另一个线程操作GUI时,此假设被破坏,您最终可能会在损坏的状态下使用GUI。

 What is the EDT? 

围绕Swing API存在的大量并发问题,这是一个hacky解决方法;)

说真的,很多Swing组件都不是“线程安全的”(一些着名的程序员甚至称为Swing“线程敌对”)。 通过拥有一个独特的线程,对这个线程恶意的组件进行所有更新,你就会避免很多潜在的并发问题。 除此之外,您还可以保证它将按顺序运行使用invokeLater传递的Runnable。

请注意,这不仅仅是因为你躲避并发问题:你必须遵守Sun关于EDT必须做什么和不能做什么的指导,否则你的应用程序会出现严重问题。

另一个好处是,一些Swing组件倾向于抛出不必要的exception,当发生这种情况时,它们会自动处理并且不会使EDT崩溃(如果你真的设法杀死EDT它会自动重启AFAIK)。

换句话说:你不必处理所有破坏的Swing组件以及他们自己抛出的exception:EDT正在处理这个问题(只是看看Sun的bug游行中抛出exception的无数Swing bug,它很吸引人。 ……然而大多数应用程序仍然正常工作)。

此外,通过仅执行EDT中的强制操作,您的应用程序的GUI可以保持“响应”,即使很难,也可能在后台运行任务。

要记住的重要一点是Swing类不是线程安全的。 这意味着您始终应该从同一个线程调用Swing方法,否则您可能会遇到奇怪或未定义的行为。

所以解决方案:只从单个线程调用Swing方法。 这是EDT线程 – 除了它是指定调用swing方法的线程之外,它并不特别。

现在您可能会问为什么Swing方法不是线程安全的? 经过几次不成功的尝试,GUI工具包设计者发现设计一个线程安全的GUI工具包本身是不可能的。 通常,事件以相反的方向传递(从下到上的输入事件,从上到下的应用程序事件),这总是导致死锁。 所以这就是它的方式。