gpt4 book ai didi

java - invokeAndWait 似乎导致应用程序间歇性卡住

转载 作者:行者123 更新时间:2023-12-04 04:48:38 25 4
gpt4 key购买 nike

发生在后台的进程会触发回调以询问各种问题。

在这种情况下,问题是“可以迁移您的数据吗?”,所以我必须询问用户。由于我们必须在 EDT 上完成所有 Swing 工作,因此最终看起来像这样(我只删除了注释、对我们自己的便利方法的引用以及 allowMigration() 的参数——除此之外,其他一切都相同):

public class UserMigrationAcceptor implements MigrationAcceptor {
private final Window ownerWindow;
public UserMigrationAcceptor(Window ownerWindow) {
this.ownerWindow = ownerWindow;
}

// called on background worker thread
@Override
public boolean allowMigration() {
final AtomicBoolean result = new AtomicBoolean();
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
result.set(askUser());
}
});
} catch (InterruptedException e) {
Thread.currentThread.interrupt();
return false;
} catch (InvocationTargetException e) {
throw Throwables.propagate(e.getCause());
}
return result.get();
}

// called on EDT
private boolean askUser() {
int answer = JOptionPane.showConfirmDialog(ownerWindow, "...", "...",
JOptionPane.OK_CANCEL_OPTION);
return answer == JOptionPane.OK_OPTION;
}
}

发生的事情是,在某些情况下,在确认或取消出现的对话框后,Swing 似乎进入以下状态:
  • JOptionPane不再可见
  • 事件队列中没有待处理的内容
  • 后台线程卡在里面 #invokeAndWait ,等待InvocationEvent#isDispatched()返回 true .

  • 我们在这里做错了什么,还是我在查看 Swing/AWT 中的错误?

    唯一值得注意的另一件事是,这是模态对话框的第二级。有一个显示操作进度的模式对话框,然后此确认对话框将进度对话框作为其父级。

    更新 1:这是 EDT 当前被阻止的地方:
    java.lang.Thread.State: WAITING
    at sun.misc.Unsafe.park(Unsafe.java:-1)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
    at java.awt.EventQueue.getNextEvent(EventQueue.java:543)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:154)
    at java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:182)
    at java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:221)
    at java.security.AccessController.doPrivileged(AccessController.java:-1)
    at java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:219)
    at java.awt.Dialog.show(Dialog.java:1082)
    at java.awt.Component.show(Component.java:1651)
    at java.awt.Component.setVisible(Component.java:1603)
    at java.awt.Window.setVisible(Window.java:1014)
    at java.awt.Dialog.setVisible(Dialog.java:1005)
    at com.acme.swing.progress.JProgressDialog$StateChangeListener$1.run(JProgressDialog.java:200)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(AccessController.java:-1)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:154)
    at java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:182)
    at java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:221)
    at java.security.AccessController.doPrivileged(AccessController.java:-1)
    at java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:219)
    at java.awt.Dialog.show(Dialog.java:1082)
    at javax.swing.JOptionPane.showOptionDialog(JOptionPane.java:870)

    这里奇怪的是 showOptionDialog()底部是迁移提示,但 Dialog#setVisible再往上是进度对话框。换句话说,有时子对话框以某种方式出现在父对话框之前,也许这就是破坏 Swing 的原因。

    更新 2:

    事实上,我可以在不使用我们自己的任何代码的情况下在测试程序中实现这一点。尽管测试程序中的对话定位不同,但它以完全相同的方式挂起,只是可重复性更高。 gist

    最佳答案

    我只是在自己的代码中遇到了同样的问题。

    您调用 JOptionPane.showOptionDialog()永远不会返回,因为当它的事件调度循环坐在那里等待用户输入时,计时器(或其他东西)已经触发并导致另一个模态对话框安装自己的事件循环。在您的堆栈中,罪魁祸首是 JProgressDialog$StateChangeListener$1.run() ,然后您可以看到它启动了自己的事件调度循环。

    在您的 JProgressDialog 关闭之前,它不会退出其循环,并且之前对 JOptionPane.showOptionDialog() 的调用将永远不会返回。

    如果对话框父级似乎暗示事件队列不支持的层次结构,这可能并不明显。

    两种解决方案可能是避免模式进度对话框,或者立即显示进度对话框。如果事件线程的其余部分乐于坐下来等待它关闭,那么从事件启动模态对话框将是一个好主意。

    关于java - invokeAndWait 似乎导致应用程序间歇性卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17781511/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com