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,则会导致另一个“事件泵”启动