java 从 EDT 调用 invokeAndWait
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2435397/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
calling invokeAndWait from the EDT
提问by Aly
I have a problem following from my previous problem. I also have the code SwingUtillities.invokeAndWaitsomewhere else in the code base, but when I remove this the gui does not refresh. If I dont remove it the error I get is:
我的上一个问题出现了问题。我SwingUtillities.invokeAndWait在代码库的其他地方也有代码,但是当我删除它时,gui 不会刷新。如果我不删除它,我得到的错误是:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
at java.awt.EventQueue.invokeAndWait(Unknown Source)
at javax.swing.SwingUtilities.invokeAndWait(Unknown Source)
at game.player.humanplayer.model.HumanPlayer.act(HumanPlayer.java:69)
The code in HumanPlayer.act is:
HumanPlayer.act 中的代码是:
public Action act(final Action[] availiableActions) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
gui.update(availiableActions);
}
});
}
catch (InterruptedException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
synchronized(performedAction){
while(!hasPerformedAction()){
try {
performedAction.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setPerformedAction(false);
}
return getActionPerfomed();
}
Image of threads when in debug as screen doesn't paint: alt text http://img684.imageshack.us/img684/6669/69288941.png
由于屏幕未绘制而调试时的线程图像: 替代文本 http://img684.imageshack.us/img684/6669/69288941.png
Text version of stack:
堆栈的文本版本:
ui.startup.LoginScreen at localhost:51050
-> Deamon Thread [AWT-Windows] (Running)
-> Thread [AWT-Shutdown] (Running)
-> Thread [AWT-EventQueue-0] (Running)
-> Thread [DestroyJavaVM] (Running)
采纳答案by Aly
The answer was instead of making the call
答案是而不是打电话
new GameInitializer(userName, player, Constants.BLIND_STRUCTURE_FILES.get(blindStructure), handState);
from the EDT, make it execute on a new (non EDT) thread so that later when invokeAndWaitis called it functions as correctly as the thread running that command is not the EDT. The amended code is as follows:
从 EDT 中,使其在新的(非 EDT)线程上执行,以便稍后invokeAndWait调用它时,它的功能与运行该命令的线程不是 EDT 一样正确。修改后的代码如下:
Thread t = new Thread(new Runnable() {
@Override
public void run() {
new GameInitializer(userName, player, Constants.BLIND_STRUCTURE_FILES.get(blindStructure), handState);
}
});
t.start();
回答by Itay Maman
invokeAndWait()is meant to be called from the non-GUI thread. It sends a Runnableobject to the GUI thread where it will be executed.
invokeAndWait()旨在从非 GUI 线程调用。它将一个Runnable对象发送到将在那里执行的 GUI 线程。
There's no point in sending a Runnableobject from the GUI-thread to itself. It has the same effect as calling run()on the Runnableobject directly.
将Runnable对象从 GUI 线程发送到自身是没有意义的。它与调用同样的效果run()上Runnable直接对象。
回答by Michael Myers
Based on the comments, it appears you are not repainting the frame once the actions are completed. If you do not, then the screen will only be updated at what seems to be random times (when another window moves in front, perhaps).
根据评论,一旦操作完成,您似乎不会重新绘制框架。如果你不这样做,那么屏幕只会在似乎是随机的时间更新(当另一个窗口移动到前面时,也许)。
Inside gui.update, I suggest you make the last line:
在里面gui.update,我建议你写最后一行:
myFrame.repaint();
(more or less, depending on your circumstances).
(或多或少,取决于您的情况)。
Edit:As it turns out, the actual problem is this loop:
编辑:事实证明,实际问题是这个循环:
synchronized(performedAction){
while(!hasPerformedAction()){
try {
performedAction.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setPerformedAction(false);
}
Since there is only one application thread (which happens to be the EDT), the result of hasPerformedAction()can never change (assuming it's a simple getter). There is no other thread to change the value. Since this infinite loop is on the EDT, the GUI can never be repainted; hence it locks up.
由于只有一个应用程序线程(恰好是 EDT),所以结果hasPerformedAction()永远不会改变(假设它是一个简单的 getter)。没有其他线程可以更改该值。由于此无限循环在 EDT 上,因此永远无法重新绘制 GUI;因此它锁定。
回答by benez
You can check before if your current calling thread is already the event dispatcher:
您可以先检查当前调用线程是否已经是事件调度程序:
private void syncExec(final Runnable r) {
try {
if (EventQueue.isDispatchThread()) r.run();
else EventQueue.invokeAndWait(r);
} catch (final Exception e) {
Throws.throwRuntime(e);
}
}
Note that SwingUtilities.invokeAndWait(Runnable)simply delegates to the EventQueue.
请注意,SwingUtilities.invokeAndWait(Runnable)只是委托给EventQueue.

