如何弄清楚我应该在GUI线程中进行函数调用

时间:2010-10-19 13:13:11

标签: java swing

我怎么知道,我是否应该在GUI线程中进行函数调用。

if (SwingUtilities.isEventDispatchThread()) {
    // ...
} else {

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            // ...
        }
    });
}

例如

// Should I call this within GUI thread?
jTable.getModel().setValueAt(...

或者

// Should I call this within GUI thread?
jComboBox.showPopup();

据我所知,在错误的线程中进行操作可能会产生不易检测的问题。因此,我很难核实我是否正在做正确的事情。

目前,我正在做的是If I am not sure, I will just call them in GUI thread

不确定这是最好的方法,还是有可靠的方法来解决?

3 个答案:

答案 0 :(得分:1)

如果你真的需要一些超级通用的东西“调用ASAP”功能,那么像这样的帮手很有用:

void invokeAsSoonAsPossible(Runnable action) {
    if (SwingUtilities.isEventDispatchThread())
        action.run();
    else SwingUtilities.invokeLater(action);
}

// Usage:
invokeAsSoonAsPossible(new Runnable(){
    @Override
    public void run() {
        jTable.getModel().setValueAt(...
    }
});

但是我的经验告诉我,构建和记录代码是一个更好的策略,以便更容易跟踪正在运行的内容。如果你在一个应该在EDT上运行的类中有一个公共方法,那么JavaDoc是一个好朋友:

/**
 * Blah blah blah, describe the method's purpose.
 * <p>
 * <strong>Note:</strong> This method should always be 
 * invoked on the Swing event dispatch thread.
 */
public Pony calulateValue() {
    // go ahead and touch the components any way you please
}

您还可以在仅EDT方法中添加断言作为一种可执行文档:

assert SwingUtilities.isEventDispatchThread();

简而言之:如果您很难跟踪自己所处的线程,那么您的代码可能非常苛刻,以至于您很难跟踪任何内容,而您应该担心重构代码,而不是你正在上线。

答案 1 :(得分:0)

实际上

if (SwingUtilities.isEventDispatchThread()) {
  // just do it, you're already in EDT
} else {
  SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        // ...
    }
  });
}

所有涉及Swing或AWT组件/类的代码都应该在EDT中运行,即。使用SwingUtilities.invokeLater(Runnable)助手。

您可以使用Substance Look&Feel配置应用以进行测试。如果UI相关代码在EDT之外运行,则抛出异常。

答案 2 :(得分:0)

几乎所有的Swing方法都需要在UI线程上执行。有一些例外(例如一些setMethods)。这些异常记录在API文档中(通常称为“此方法是线程安全的”)。 然而,一般规则是所有 GUI更新应该在UI线程上进行。


在大多数情况下,你应该知道你当前在哪个线程。这很容易辨别。 GUI事件触发的所有回调都在UI线程上执行,主线程和您启动的所有其他线程中的操作不在UI线程上。

如果您有时会从自己的线程中调用代码,有时也会从UI线程调用代码,您可以像在问题中显示的那样,通过调用EventQueue.isDispatchThread()来确定您是否在UI线程上

我会将代码放在一个单独的方法updateGuiComponent(...)中执行

if (EventQueue.isDispatchThread())
    updateGuiComponent(...);
else
    SwingUtilities.invokeLater(new Runnable() {          // or invokeAndWait
        public void run() { updateGuiComponent(...); }
    });