Multithreading 代码名1:需要访问UI的后台线程
我的应用程序有需要访问UI的后台线程。 想象一下,一个国际象棋程序(AI)在棋盘上下棋之前会“思考”几秒钟。 线程运行时,UI被阻止输入,但仍有输出 涉及3个线程:Multithreading 代码名1:需要访问UI的后台线程,multithreading,user-interface,codenameone,edt,Multithreading,User Interface,Codenameone,Edt,我的应用程序有需要访问UI的后台线程。 想象一下,一个国际象棋程序(AI)在棋盘上下棋之前会“思考”几秒钟。 线程运行时,UI被阻止输入,但仍有输出 涉及3个线程: 美国东部夏令时 使用invokeAndBlock的think线程,输出有关搜索过程的信息(在文本字段中),例如当前移动、搜索深度和搜索值 一个时钟线程,以thread.start()开头,每秒更新一次白色或黑色(TextFields)使用的时间 在搜索过程中(invokeAndBlock),可以使用stop按钮强制停止搜索(未显示)
// version 2, replaced invokeAndBlock by Thread.start() and callSerially
void think() {
blockUI(); // disable buttons except stopButton
new Thread(() -> { // off the EDT
clock.start(board.player); // this thread calls showWhiteTime or showBlackTime every second
move = search(board, time); // e.g. for 10 seconds
clock.stop();
callSerially(() -> {
animateMove(board, move);
clock.start(board.player);
freeUI();
});
}).start();
}
// version 2, added callSerially
void showWhiteTime(String s) { // access UI off the EDT
callSerially(() -> {
whiteTime.setText(s);
});
}
// version 2, added callSerially
void showBlackTime(String s) { // access UI off the EDT
callSerially(() -> {
blackTime.setText(s);
});
}
虽然我可以避免您在
showWhiteTime
和showBlackTime
中遇到的EDT冲突,但大多数代码都很好。EDT违规可能会以奇怪的方式突然失败,因为您触发异步操作,事情可能会很快变得糟糕。我建议在模拟器中打开EDT违规检测工具
使用invokeAndBlock
时要记住两件事:
- 它比普通线程慢
- 在某些情况下,它会阻止挂起事件,因此将其作为挂起事件链的一部分是有问题的
buttonA.addActionListener(e -> {
doStuff();
invokeAndBlock(...);
doOtherStuff();
});
buttonA.addActionListener(e -> doSomethingImportant());
这可能看起来不现实,因为您通常不会一个接一个地添加两个单独的侦听器,但这种情况已经足够了,例如,如果一个更改触发另一个更改,等等
在invokeAndBlock
期间,buttonA
的当前事件处理将被阻止。这意味着doOtherStuff()
将等待invokeAndBlock
并且doSomethingImportant()
将等待
如果doSomethingImportant()
显示另一个表单,您可能会出现奇怪的行为,例如在您按下按钮并做了许多其他事情之后,您的表单会突然发生变化
因此,您需要非常清楚如何使用
invokeAndBlock
Re“需要访问UI的后台线程”。不要这样做。UI线程和其他线程之间的耦合应该非常松散。UI线程应该显示程序的状态。当其他线程以用户可能希望看到的方式更改该状态时,它们应该能够通知UI。UI应该能够通知后台线程,用户已经以可能很重要的方式更改了状态。但大多数情况下,它们应该彼此独立运行。例如,“blockUI()…search()…freeUI()”。也不要去那里。用户界面应该始终对用户操作做出响应,即使响应只是说:“你现在不能这样做,因为轮到你移动了。”没有响应的用户界面会产生一种错觉,认为你的程序不可靠,即使它不可靠。一个简洁的用户界面会让人产生一种错觉,认为你的程序比实际速度快。“不要去那里”不是一个有用的答案。你曾经使用过国际象棋程序吗?这不是一个答案。旨在作为替代设计建议。是的,我不是一个认真的球员,但我曾经和一台机器对抗过。我不会向我的任何朋友推荐一个象棋程序,如果它的用户界面在“思考”时被锁定。好的,谢谢,我会考虑的。但问题其实是关于代码名一线程和访问用户界面。谢谢你的回答。是的,我已经在模拟器中使用了完整的EDT违规检测。如果我在showSearchInfo中不连续使用callSerially,它会报告违规行为。但是,它不会报告showWhiteTime和showBlackTime中的违规行为。我是否正确理解您建议在这些方法中也使用callSerially?(请参阅有问题的编辑。)您是否也建议在这种情况下避免invokeAndBlock?think()的第2版怎么样?(参见有问题的编辑。)违规检测并不完美。它可能会错过一些问题,并对一些不存在的问题保持警惕。是的,如果您从单独的线程访问UI,即使违例检测工具没有检测到,也应该使用callSerially。异步方法会更快,但可读性较差。这是你的选择,两者都会起作用。
buttonA.addActionListener(e -> {
doStuff();
invokeAndBlock(...);
doOtherStuff();
});
buttonA.addActionListener(e -> doSomethingImportant());