可以在EDT线程的非EDT线程上调用Future.get()吗?

时间:2016-01-21 15:57:30

标签: java swing concurrency edt

这是在单元测试的背景下(正好)。

在测试结束时,无论结果如何,我都希望代码检查JFileChooser对话框的存在(可见性)......如果可见,则将其解除。

当然,有不同的方法可以解雇对话,但是为了模仿人类行为(并举出我在这里关注的那类问题的例子),我选择使用java.awt.Robot。后者的方法应该在非EDT线程中运行。

事实上,我已经扩展了Robot以包含一个名为type_input的便捷方法,所以

robot.type_input( KeyEvent.VK_F4, KeyEvent.VK_ALT )

按下第一个Alt,然后按F4,然后释放F4然后按Alt:就像人类解雇窗口/对话框一样。

我使用Runnable提交invokeAndWait因为我不希望代码在下一次测试之前运行,直到此对话框被解除。我必须测试能见度和焦点在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() );
    }

}

正如我在回答中所说的那样,这并不是针对手头案例的特定实际解决方案:我真的想了解是否以及何时使用另一个EDT&#34;事件泵&#34;以Future.get()阻止EDT开始。 正如我所说,我发现整个方面很难理解。我使用JOptionPane的静态方法(必须在EDT中运行,请参阅关于SO ad haauseam的帖子)向我展示这些方法(阻止EDT!)不要实际上似乎阻止了GUI的运行(注意不要混淆这些JOptionPane,或者更确切地说它们JDialog是模态的还是无模式的。

我的理解是,这是因为&#34;框架&#34;然后启动另一个&#34;事件泵&#34;。它可以这样做吗?

2 个答案:

答案 0 :(得分:2)

所以,来自JavaDocs

  

如果需要等待计算完成,然后检索其结果。

这表明该方法是一种阻塞方法,如果在事件调度线程的上下文中你不应该做一件事,它就会在事件调度线程的上下文中调用阻塞方法

啊,但该怎么办?您可以使用SwingWorker代替ExecutorService,内部使用自己的submit,或ExecutorService工作人员使用SwingWorker Runnable实施PropertyChangeListener ),您应该能够使用SwingWorker来监控DONE的状态,当它是get时,您可以从config/redis/cable.yml方法中检索该值而不会阻止

答案 1 :(得分:0)

在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 );
}
相关问题