简介
Swing 应用程序中的事件分派线程(EDT)负责处理与用户交互相关的事件。为了保持界面的响应性,需要谨慎地访问和修改 GUI 组件。invokeAndWait 和 invokeLater 是 SwingUtilities 类中的两个方法,用于从非 EDT 线程与 GUI 组件进行交互。理解这两个方法之间的区别对于构建响应且稳定的 Swing 应用程序至关重要。
invokeAndWait
invokeAndWait 方法从调用线程阻塞地执行给定的 Runnable。这意味着调用线程将等待 Runnable 完成执行,然后继续执行。invokeAndWait 的语法如下:
public static void invokeAndWait(Runnable runnable) throws InterruptedException, InvocationTargetException;
特性:
- 阻塞:
invokeAndWait方法将阻塞调用线程,直到Runnable完成执行。 - 同步:
invokeAndWait保证Runnable将在 EDT 上执行,并且在Runnable完成执行之前,EDT 上不会执行任何其他操作。 - 异常处理:如果在
Runnable中引发异常,则该异常将被 rethrown 为InvocationTargetException.
优点:
- 确保 GUI 一致性:
invokeAndWait保证 GUI 在Runnable执行期间保持一致,因为 EDT 在此期间被阻塞。 - 获取返回值:
invokeAndWait允许从Runnable获取返回值,因为它在调用线程上执行。 - 同步更新:如果
Runnable需要更新 GUI 组件,则invokeAndWait可以确保这些更新在Runnable完成执行之前完成。
缺点:
- 阻塞调用线程:
invokeAndWait会阻塞调用线程,从而可能导致应用程序无响应。 - 性能影响:频繁使用
invokeAndWait可能会影响应用程序的性能,因为它会导致调用线程被阻塞。
invokeLater
invokeLater 方法将给定的 Runnable 异步调度到 EDT。这意味着 Runnable 将在某个时间点在 EDT 上执行,但不是立即执行。invokeLater 的语法如下:
public static void invokeLater(Runnable runnable);
特性:
- 非阻塞:
invokeLater方法不会阻塞调用线程。 - 异步:
invokeLater调度的Runnable将在不确定的时间点在 EDT 上执行。 - 无返回值:
invokeLater不允许从Runnable获取返回值,因为它是在不同的线程上执行的。
优点:
- 保持响应性:
invokeLater不阻塞调用线程,因此应用程序可以继续对用户交互做出响应。 - 提高性能:异步调度有助于分散对 EDT 的负载,从而提高应用程序的整体性能。
缺点:
- 不保证 GUI 一致性:由于
invokeLater是异步的,因此在Runnable执行期间 GUI 可能会发生变化。 - 无返回值:
invokeLater不允许从Runnable获取返回值。 - 异常处理:如果在
Runnable中引发异常,则无法在调用线程中捕获该异常。
比较
| 特性 | invokeAndWait | invokeLater |
|---|---|---|
| 同步性 | 同步 | 异步 |
| 阻塞 | 是 | 否 |
| GUI 一致性 | 保证 | 不保证 |
| 返回值 | 可获取 | 不可获取 |
| 性能影响 | 可能影响 | 影响较小 |
| 响应性 | 可能降低 | 保持 |
| 异常处理 | 抛出 InvocationTargetException | 无法捕获 |
何时使用
使用 invokeAndWait:
- 当需要确保 GUI 在给定的
Runnable执行期间保持一致时。 - 当需要从
Runnable中获取返回值时。
使用 invokeLater:
- 当需要保持应用程序的响应性时。
- 当
Runnable不需要修改 GUI 组件或获取返回值时。
最佳实践
- 尽量使用 invokeLater:使用
invokeLater而不是invokeAndWait将有助于提高应用程序的性能和响应性。 - 仅在必要时使用 invokeAndWait:只有在确实需要保证 GUI 一致性或获取返回值时才使用
invokeAndWait。 - 使用 try-catch 块处理异常:在
Runnable中使用 try-catch 块捕获异常,并在调用线程中检查InvocationTargetException以获取任何抛出的异常。
总结
invokeAndWait 和 invokeLater 是在 Java Swing 应用程序中与 GUI 组件进行交互的两个重要方法。理解它们的差异对于编写响应且稳定的应用程序至关重要。通过明智地选择合适的方法,可以平衡 GUI 一致性、性能和响应性之间的权衡。