我的自定义事件是应该在GUI EDT还是“本土”EDT上启动

时间:2012-10-17 18:05:05

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

我正在研究一个强大的数学计算(矩阵,向量等数组)的项目,所以很自然地我将工作分成工作,并将它们提交给CompletionService以并行执行工作

每个作业对象都可以触发事件,以便在作业开始,结束,进展和/或失败时通知应用程序。

目前,每个作业都会收到整个事件侦听器列表的句柄,并简单地遍历,将事件对象传递给每个作业(在同一个线程中)。这对我来说并不合适,所以我想让其他人通过自定义事件/听众来做这类事情。

我应该将我的活动发送到GUI线程吗?一些监听器可能与GUI有关,也可能不与GUI有关,我不想强​​迫我的代码用户必须手动将他们的事件发送到GUI线程,如下所示:

public class MyFooEventListener implements FooEventListener {
    public void notifyJobStarted(FooEvent evt) {
        // I want to avoid having users of my library write the following, right?
        SwingUtilities.invokeLater(new Runnable(){
            // update GUI here.
        });
    }
}

我不介意编写自己的EventQueue,因为这是针对学校的一个研究项目,我想这将是一个很好的并发练习。只是想弄清楚实现事件驱动系统的“正确”方法是什么,如何正确地触发事件等。文章/教程和howtos的链接也非常感谢。

谢谢!

修改

我的活动模型有多种活动类型,例如JobStartedEventJobEndedEventJobProgressEvent等。这是一种不好的做法吗?我应该只有一个事件类型,如果是这样,我如何将信息传递给所有事件不常见的侦听器?示例:我想在进度事件的[0-1]范围内传递一个double,但这不适用于像JobFailureEvent这样的事件。处理此问题的最佳方法是什么?

我可以将额外的信息放在“源”对象本身中,但我的源对象本身就是Job对象,并且它不适合我“泄漏”对作业对象的引用,特别是当它是运行:

FooJob jobObject = (FooJob)event.getSource();
int progressPercent = jobObject.getCurrentProgress() * 100;
progressLabel.setText(progressPercent + "%");

4 个答案:

答案 0 :(得分:4)

没有。在任何需要引发它们的线程上发布您的事件,并将其留给子系统的用户来决定他们希望如何处理它们。如果他们希望将结果发送到GUI,那么很好,如果没有,他们可以做任何他们想做的事情,例如。将它们排队到另一个线程。只记录'事件是在内部线程上引发的,事件处理程序不能阻止'。

正如你所说,其他任何事情都会对他们可能不想要的用户施加限制。

答案 1 :(得分:3)

分发活动的方式有很多种,每种方式各有利弊。如果消费者不一定是GUI,那么你绝对不应该把自己束缚在EDT上。除非你确定事件消费者将如何工作,否则我会从简单开始。简单的存在:同步通知每个消费者。如果最终延迟主要任务,那么你应该考虑异步通知。如果消费者最终是GUI,那么消费者的通知方法应该负责调用SwingUtilities.invokeLater

答案 2 :(得分:1)

只有直接影响GUI的线程才能在EDT上。如果您有其他线程需要同步,只需使用synchronized关键字(在方法或对象上)

答案 3 :(得分:0)