【问题标题】:Stopping a running process via GUI, in java在java中通过GUI停止正在运行的进程
【发布时间】:2016-02-15 06:41:05
【问题描述】:

我有一个执行 TestNG 自动化脚本的 GUI 程序。它旨在让用户轻松配置一些设置并启动他们想要的自动化脚本。

我需要添加的一件事是能够立即停止正在运行的 TestNG 进程。就像在 Eclipse 中一样,“终止”按钮会立即停止正在运行的任何内容。

这是启动 TestNG 测试的代码的样子:

public class ScriptRunner implements Runnable {

    public void runScript() {
        Thread testRun = new Thread(this);
        testRun.start();
    }

    @Override
    public void run() {
        //various other things are configured for this, 
        //but they're not relevant so I left them out
        TestNG tng = new TestNG();

        //While this runs, various browser windows are open, 
        //and it could take several minutes for it all to finish
        tng.run();
    }
}

根据评论,tng.run() 可能需要几分钟才能完成,它正在执行几件事,打开/关闭浏览器窗口等。

我怎样才能像从 IDE 运行应用程序一样立即终止进程?

编辑:

根据 cmets,我正在尝试使用 ServiceExecutor 和 shutDownNow() 代码如下所示:

ExecutorService executorService = Executors.newFixedThreadPool(10);

public void runScript() {
    executorService.execute(this);
}

//this method gets called when I click the "stop" button
public void stopRun() {
    executorService.shutdownNow();
}

@Override
public void run() {
    //same stuff as from earlier code
}

【问题讨论】:

  • System.exit(0);将立即终止 JVM
  • @OluCode 是的,但这不会也杀死我的 GUI 应用程序吗?我需要一种方法来杀死正在运行的 TestNG 对象。
  • 如果是线程,使用像ExecutorService这样的线程管理器为你处理线程生命并调用serviceObject.shutDownNow();
  • 为什么不将TestNG 线程保存在run() 方法范围之外并从另一个方法终止它?
  • @OluCode 谢谢,但它似乎不起作用。 shutdownNow();仅停止 TestNG 对象正在执行的直接操作(例如,如果对象必须在单独的浏览器中分别运行 10 个测试,则调用 shutDownNow() 一次仅停止 1 个测试)

标签: java user-interface testng terminate


【解决方案1】:

我最近正在研究执行器框架。在这里我列出了我的问题 http://programtalk.com/java/executorservice-not-shutting-down/

注意,如果你在做一些 IO 操作,executor 服务可能不会立即关闭。如果您看到下面的代码stopThread 很重要,因为它告诉您的程序线程已被要求停止。你可以停止一些你正在做的迭代。 我会这样修改你的代码:

public class MyClass {

private ExecutorService executorService;

private boolean stopThread = false;

public void start() {
   // gives name to threads
    BasicThreadFactory factory = new BasicThreadFactory.Builder()
             .namingPattern("thread-%d").build();
    executorService =  Executors.newSingleThreadExecutor(factory);
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            try {
                doTask();
            } catch (Exception e) {
                logger.error("indexing failed", e);
            }

        }
    });
    executorService.shutdown();
}

private void doTask()  {
    logger.info("start reindexing of my objects");
    List<MyObjects> listOfMyObjects = new MyClass().getMyObjects();
    for (MyObjects myObject : listOfMyObjects) {
        if(stopThread){ // this is important to stop further indexing
            return;
        }
        DbObject dbObjects = getDataFromDB();
        // do some task
    }
}



public void stop() {
    this.stopThread = true;
    if(executorService != null){
        try {
            // wait 1 second for closing all threads
            executorService.awaitTermination(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

}

【讨论】:

    【解决方案2】:

    保存所有创建的进程并在程序结束时终止它们:

    public class ProcessFactory {
      private static Set<Process> processes = new HashSet<>();
      private static boolean isRunning = true;
    
      public static synchronized Process createProcess(...) throws ... {
        if (!isRunning)
          throw ...
        ... // create your spawned process
        processes.add(process);
        return process;
      }
    
      public static synchronized void killAll() {
        isRunning = false;
        for (Process p : processes)
            p.destroy();
        processes.clear();
      }
    
      public static void registerShutdownHook() {
          Runtime.getRuntime().addShutdownHook(new Thread() {
             void run() {
                 killAll();
             }
          });
      }
    }
    

    这可以通过添加一种机制来移除已经死掉的进程来改进,但你明白了。

    【讨论】:

      【解决方案3】:

      在你的图形用户界面中,你有类似的东西

      ScriptRunner scriptRunner = new ScriptRunner();
      scriptRunner.runScript();
      

      当你想停止它时调用

      scriptRunner.interrupt();
      

      修改ScriptRunner中的代码

      private Thread testRun;
      public void runScript() {
          testRun = new Thread(this);
          testRun.start();
      }
      
      public void interrupt() {
          testRun.interrupt();
      }
      

      【讨论】:

        【解决方案4】:

        一个新线程怎么样?您必须在 gui 中添加 private Thread thread; 以及何时开始

        thread = new thread(){
            @Override
            public void run(){
               //start process here
            }
        };
        thread.start();
        

        并停止“终止”

        thread.stop();(已弃用)或thread.setDeamon(true);

        每次我必须通过 gui 停止一个进程时,我都会使用它。

        希望我能帮上忙;)

        【讨论】:

          【解决方案5】:

          这个呢, 添加一个 volatile 静态布尔值并使线程代码看起来像...

          if(ScriptRunner.runThread){
              //Do some stuff here
          }
          if(ScriptRunner.runThread){
              //Do some other stuff here
          }
          if(ScriptRunner.runThread){
              //Do some other stuff here
          }
          if(ScriptRunner.runThread){
              //Do rest of the stuff here
          }
          

          现在您可以在主 GUI 中添加一个按钮,该按钮只需将 runThread 设置为 false,以便线程几乎会立即终止,而当您按下 Stop 按钮时,所有剩余代码都不会受到影响。

          public class ScriptRunner implements Runnable {
          
              volatile static Boolean runThread = true;
          
              public void runScript() {
                  Thread testRun = new Thread(this);
                  testRun.start();
              }
          
              public void terminate(){
                  runThread = false;
              }
          
              @Override
              public void run() {
                  //various other things are configured for this, 
                  //but they're not relevant so I left them out
                  TestNG tng = new TestNG();
          
                  //While this runs, various browser windows are open, 
                  //and it could take several minutes for it all to finish
                  tng.run();
              }
          }
          

          【讨论】:

            【解决方案6】:

            您可以使用 ExecutorService 开始测试执行到另一个线程。您可以通过选择您需要的执行器服务来选择并行处理多个线程或仅一个线程用于所有测试。

            之后,通过调用 submit() 方法在同一个执行器服务实例中开始执行所有测试。你可以通过调用shutdownNow()方法来停止所有提交的runnables的执行。

            使用相同的 ExecutorService 实例很重要,否则您将在不同的线程中启动每个测试,并且您将无法中断执行链(或通过在所有线程上调用 shutdownNow())。

            【讨论】:

              【解决方案7】:

              使用 ProcessBuilder 或 Runtime 生成一个子 JVM 进程,当用户请求脚本停止运行时,您将能够终止该进程。

              【讨论】:

                最近更新 更多