【发布时间】:2024-04-29 15:00:02
【问题描述】:
好的,所以解释这种情况有点复杂。它实际上并不像看起来那么危险。
我正在编写一个并发包,它做两件事,它曾经在 JDK 6 上完美运行。它所做的第一件事是提供一个更好的Future 接口,它允许在任务完成时使用事件侦听器进行回调。 “但你可以使用FutureTask 的done()!”你可能会说。问题是当一个任务被取消时,done() 会立即被调用,而该任务可能仍在其call() 方法中做一些事情。此外,取消使得无法检索部分结果。所以我自己的包通过扩展现有的包来解决这些问题(包括一个新的线程池,但大部分实现都在那里重用)。
包做的第二件事是解决一个常见的 GUI 问题。假设用户单击“保存”以保存图像。如果图像很大,最好显示进度监视器而不是冻结界面。但是如果文档很小,那么进度监视器的突然闪烁会使用户感到困惑。而且我们不能有最小的弹出时间 - 这会减慢工作流程。我的解决方案在这两者之间妥协。效果是 EDT “冻结”了任务完成所需的时间,或者,如果花费的时间超过 1 秒,则显示一个具有最短弹出时间的进度监视器。效果相当优雅。这在 JDK6 中也可以完美运行,甚至可以使用多个线程。
问题:在 JDK7 中,上面的冻结部分现在有一个微妙的错误。我的代码的一个关键假设是传递给由于实施错误,没关系。SwingUtilities.invokeLater() 的Runnable 将不会 与其他事件调度线程的东西同时运行。所以 EDT 不能在 Runnable 运行时处理按钮点击、加速器、其他事件等。 (这被用来在冻结期间停止所有输入)但这似乎在 JDK7 中发生了变化。在我的调试中,我注意到Runnable 可能正在运行,而按下按钮的代码仍在运行!由于后来的事情,这很快就会导致死锁。
像这样滥用 EDT 是有风险的,但在过去,这是唯一有效的方法。一些人建议使用GlassPane 来拦截事件。但它不能拦截加速器。我当时尝试的其他一切也都以这种方式受到限制。
我现在的问题是,是否有人找到更好的方法来做到这一点。如果您认为我的Future 问题可以以更好的方式解决,请告诉我。最重要的是,如果您能找到解决上述 GUI 问题的方法,或者停止输入,或者保证我在 JDK 上需要的关键假设,或者提出长期解决方案 - 所有这些都非常感谢。谢谢!
【问题讨论】:
-
SwingUtilities.invokeXxx在事件调度线程的上下文中执行Runnable,所以我看不出如何,当执行Runnable时,您可能正在执行其他代码EDT 的上下文,因为Runnable将阻塞 EDT,直到它完成。这不会阻止事件被堆叠,只是被处理。您可以考虑使用JXLayer或(Java 7 中的JLayer)来禁用/阻止部分 UI... -
好的,将研究 JLayer。同时,让我制作一个 sn-p 来向您展示这种效果。
-
ACH!这与 Java 版本无关。这是由于一个微妙的实现错误。无论如何,我可能会将 JLayer 视为一种更强大的方式来做我想做的事。对于问题的第一部分,我将保留问题。谢谢!
-
I don't believe,为了获得更好的帮助,请尽快发布 SSCCE,简短,可运行,可编译,由上午问题引起,or there,...等
-
您知道,当我们第一次使用我们的应用程序测试 Java 7 时遇到了死锁问题,该问题发生在 Swing.invokeLater。但是在我为该部分重新编写代码后,它现在可以工作了。
标签: java multithreading swing user-interface