SwingUtilities.invokeAndWait()
是Swing 框架提供的一个方法,用于将一个 Runnable
对象放入事件派发线程(Event Dispatch Thread,EDT)并等待其执行完毕。它的主要作用是在非EDT 线程中安全地更新Swing 组件,确保对UI 的访问是线程安全的。与 SwingUtilities.invokeLater()
类似,但 invokeAndWait()
会阻塞调用线程,直到EDT 完成了任务的执行。
主要功能和作用:
-
线程安全地更新UI:
Swing 组件是线程不安全的,只能在EDT 中进行访问和修改。
invokeAndWait()
确保了在非EDT 线程中更新UI 的操作被安全地放入EDT 中执行。 -
同步执行:
invokeAndWait()
类似于一个同步调用,它会阻塞当前线程,直到EDT 执行完指定的任务并返回。 -
替代
invokeLater()
的场景:当需要立即获取任务执行结果,并且当前线程需要等待时,可以使用
invokeAndWait()
替代invokeLater()
。
使用场景:
-
需要立即获取UI 状态:
当一个线程需要获取某个UI 组件的当前状态(例如,文本框中的文本内容)时,可以使用
invokeAndWait()
确保在获取状态之前,EDT 已经完成了对该组件的更新。 -
防止死锁:
在某些情况下,使用
invokeAndWait()
可以避免死锁。例如,当一个线程需要等待另一个线程持有的锁,并且该锁的释放操作需要在EDT 中完成时,可以使用invokeAndWait()
将释放锁的操作放入EDT 中执行。
代码示例:
Java
import javax.swing.*;
import java.lang.reflect.InvocationTargetException;
public class InvokeAndWaitExample {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("InvokeAndWait Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setVisible(true);
// 在非 EDT 线程中更新 UI
new Thread(() -> {
try {
SwingUtilities.invokeAndWait(() -> {
// 在 EDT 中执行的代码
frame.setTitle("Updated Title");
System.out.println("Title updated in EDT");
});
// EDT 执行完毕后,继续执行后续代码
System.out.println("Title update complete");
} catch (InterruptedException | InvocationTargetException e) {
e.printStackTrace();
}
}).start();
});
}
}
注意事项:
-
避免在EDT 中调用
invokeAndWait()
:如果在EDT 中调用
invokeAndWait()
,会导致死锁,因为EDT 会等待自己执行完毕。可以通过SwingUtilities.isEventDispatchThread()
方法来判断当前线程是否为事件分派线程(EDT),若返回true
,表示当前线程是EDT线程 -
尽量使用
invokeLater()
:除非必须,否则应尽量使用
invokeLater()
,因为它不会阻塞调用线程,避免潜在的性能问题。 -
处理异常:
invokeAndWait()
方法可能会抛出InterruptedException
和InvocationTargetException
两种异常,需要进行适当的异常处理。
总结:
SwingUtilities.invokeAndWait()
是一个强大的工具,用于在非EDT 线程中安全地更新Swing 组件。理解其工作原理和注意事项,可以帮助开发者编写更加稳定和高效的Swing 应用程序。