Java 从EDT线程在非EDT线程上调用Future.get()可以吗?
这是在单元测试的上下文中(实际上) 在测试结束时,无论结果如何,我都希望代码检查Java 从EDT线程在非EDT线程上调用Future.get()可以吗?,java,swing,concurrency,edt,Java,Swing,Concurrency,Edt,这是在单元测试的上下文中(实际上) 在测试结束时,无论结果如何,我都希望代码检查JFileChooser对话框的存在(可见性)。。。如果可见,则将其忽略 当然,有不同的方法可以关闭对话框,但是为了模仿人类的行为(并给出我在这里关注的问题的一个例子),我选择使用java.awt.Robot。后者的方法应该在非EDT线程中运行 事实上,我已经扩展了Robot,加入了一个名为type\u input的方便方法,所以 robot.type_input( KeyEvent.VK_F4, KeyEvent.
JFileChooser
对话框的存在(可见性)。。。如果可见,则将其忽略
当然,有不同的方法可以关闭对话框,但是为了模仿人类的行为(并给出我在这里关注的问题的一个例子),我选择使用java.awt.Robot
。后者的方法应该在非EDT线程中运行
事实上,我已经扩展了Robot,加入了一个名为type\u input
的方便方法,所以
robot.type_input( KeyEvent.VK_F4, KeyEvent.VK_ALT )
先按Alt,然后按F4,然后释放F4,然后按Alt:就像人类关闭窗口/对话框一样
我使用invokeAndWait
提交Runnable
,因为我不想让代码运行到下一个测试,直到这个对话框被取消。我必须在EDT中测试可见性和焦点。但是,正如我所说,机器人方法必须在非EDT中运行
在EDT中这样执行get()
是否存在任何潜在问题?它是否可能导致GUI无响应?问题是,我听说该框架能够在特定条件下“启动新的EDT泵”。我必须承认,这是EDT相关事宜中我觉得我所知最少的一个方面
import java.awt.EventQueue;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
class MainFrame extends JFrame {
JFileChooser update_target_file_chooser;
JDialog file_chooser_dlg;
// ... rest of class
}
public class ThreadWithinThread {
public static void main(String[] args) throws InvocationTargetException, InterruptedException {
final ExecutorService thread_pool_exec_serv = Executors.newFixedThreadPool( 5 );
class DismissDlg implements Runnable {
MainFrame main_frame;
Robot robot;
@Override
public void run() {
boolean focus_on_dlg = main_frame.file_chooser_dlg.hasFocus();
if( main_frame.file_chooser_dlg.isVisible() ){
if( ! focus_on_dlg ){
main_frame.file_chooser_dlg.requestFocus();
}
class AltF4 implements Callable<Void>{
public Void call(){
return robot.type_input( KeyEvent.VK_F4, KeyEvent.VK_ALT );
}
}
Future<Void> future_result = thread_pool_exec_serv.submit( new AltF4() );
try {
// this is the line I'm worried about
future_result.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
EventQueue.invokeAndWait( new DismissDlg() );
}
}
导入java.awt.EventQueue;
导入java.awt.Robot;
导入java.awt.event.KeyEvent;
导入java.lang.reflect.InvocationTargetException;
导入java.util.concurrent.BlockingQueue;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入java.util.concurrent.ThreadPoolExecutor;
导入javax.swing.JDialog;
导入javax.swing.JFileChooser;
导入javax.swing.JFrame;
类大型机扩展JFrame{
JFileChooser更新\u目标\u文件\u选择器;
JDialog文件\u选择器\u dlg;
//…其他同学
}
公共类ThreadWithinThread{
公共静态void main(字符串[]args)抛出InvocationTargetException、InterruptedException{
final ExecutorService thread\u pool\u exec\u serv=Executors.newFixedThreadPool(5);
类DismissDlg实现Runnable{
主机主框架;
机器人;
@凌驾
公开募捐{
boolean focus_on_dlg=main_frame.file_chooser_dlg.hasFocus();
if(main\u frame.file\u chooser\u dlg.isVisible()){
如果(!集中精力){
main_frame.file_chooser_dlg.requestFocus();
}
类AltF4实现了可调用的{
公开作废通知(){
返回robot.type_输入(KeyEvent.VK_F4,KeyEvent.VK_ALT);
}
}
Future\u result=thread\u pool\u exec\u serv.submit(new AltF4());
试一试{
//这是我担心的线路
future_result.get();
}捕获(中断异常|执行异常e){
e、 printStackTrace();
}
}
}
}
invokeAndWait(newdismissdlg());
}
}
以后
正如我在回答中所说的,这并不是关于手头案件的具体实际解决方案:我真的在试图了解另一个EDT“事件泵”是否以及何时启动Future.get()
阻止EDT。
正如我所说的,我发现这整个方面很难理解。我使用的JOptionPane
的静态方法(必须在EDT中运行,请参阅文章中的内容)向我表明,这些方法(确实阻止了EDT!)实际上似乎并没有阻止GUI运行(注意不要混淆这些JOptionPane
s,或者更确切地说,它们的JDialog
s是模态的还是非模态的)
我的理解是,这是因为“框架”随后启动了另一个“事件泵”。因此,它可以在这里这样做吗?因此,从
如有必要,等待计算完成,然后检索其结果
这表明该方法是一种阻塞方法,如果在事件调度线程的上下文中有一件事你不应该做,那就是在事件调度线程的上下文中调用阻塞方法
啊,但是怎么办呢?你可以用一个
SwingWorker
来代替,它在内部使用自己的ExecutorService
,或者将工作人员提交给你自己的ExecutorService
(SwingWorker
实现可运行的),然后您应该能够使用PropertyChangeListener
来监视SwingWorker
的状态,当完成时,您可以从它的get
方法中检索值,而无需阻塞在EDT上执行必要的步骤,并向测试线程发出是否需要额外步骤的信号:
class PrepDlgDismiss implements Runnable {
boolean file_chooser_visible;
@Override
public void run() {
boolean focus_on_dlg = main_frame.file_chooser_dlg.hasFocus();
if( main_frame.file_chooser_dlg.isVisible() ){
file_chooser_visible = true;
if( ! focus_on_dlg ){
main_frame.file_chooser_dlg.requestFocus();
}
}
}
}
PrepDlgDismiss task = new PrepDlgDismiss();
EventQueue.invokeAndWait( task );
if( task.file_chooser_visible ){
robot.type_input( KeyEvent.VK_F4, KeyEvent.VK_ALT );
}
获取对JFileChooser的引用并调用isVisible,然后调用setVisible(false)会有多困难?@Bill谢谢-事实上,我主要关心的是使用Future.get()是否会在另一个EDT事件发生时导致另一个“事件泵”。这并不是说我在寻找“某些解决方案”时遇到实际困难。这只是一个想法。可能是你无法访问该对话框,但可能是你可以。有时我们会被更复杂的答案所困扰,以至于忘记了简单的东西。谢谢……是的,我知道所有关于SwingWorker的知识,并且一直在使用它。我问题的重点是了解是否使用Future.get()如果另一个EDT事件为ge,则会导致另一个“事件泵”启动