繁体   English   中英

如果FX线程在Java中终止,则终止线程的最有效方法

[英]Most efficient way to terminate a Thread if an FX thread is terminated in Java

我编写了一个简单的JavaFX应用程序,该应用程序显然在FX应用程序线程上运行。 该应用程序需要在单独的线程(不是FX线程)上运行的无限循环中进行一些后台处理,在固定的时间间隔后,我调用Platform.runLater()来更新FX应用程序的gui控件。 如果我关闭FX Gui应用程序,则后台线程将继续执行它。

为了在FX线程终止后终止后台线程,我现在在后台线程的while循环中使用fxThread.isAlive() 这样,当while循环条件变为false时,一旦FX线程终止,后台线程就会自动终止。

这是一个不好的选择吗? 完成同一任务的替代方法和有效方法有哪些?

//imports
public class SimpleClockFX implements Application{  
Thread fxThread;  
 //other variables  

@Override  
public void start(Stage primaryStage){  
    fxThread = Thread.currentThread();  

    //other stuff...  

    new Thread(()->{  
    //logic...  
      while(fxThread.isAlive()){  
          //logic...  
                  Platform.runLater(()->{
                      //update gui controls
                  });
      }  
    }).start();  

}

通过调用fxThread.isAlive()并不是最好的解决方案,因为在最坏的情况下,线程通过fxThread.isAlive()并进入Platform.runLater时,您的fxThread可能会死掉。例外,除非这是适合您情况的适当终止

尝试在顶级阶段为close事件添加一个侦听器。

还要调用System.exit(0)以完全终止JVM或所需的任何自定义终止方法(如果它仍在运行,则显式导致对后台线程的中断)。

    @Override
    public void start(Stage primaryStage) 
    {
        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            public void handle(WindowEvent we) {
                System.out.println("Stage is closing");
                System.exit(0);
            }
        });  

        primaryStage.setTitle("Hello World!");
//      add your components
        primaryStage.show();
//      not daemon
        new Thread(new CustomRunnable()).start();

    }

    private static class CustomRunnable implements Runnable
    {
        public void run() 
        {

            while(true){
//              long operation
            }
        }
    }

编辑:

根据@ lostsoul29 comment,该方案意味着生成线程将不是守护程序线程。 如果任何线程被标记为守护程序,则将需要自定义终止/处理。

如果线程不需要在终止时进行任何清理,则只需将该线程设为守护线程:

thread.setDaemon(true)

将此线程标记为守护程序线程或用户线程。 当仅运行的所有线程都是守护程序线程时,Java虚拟机将退出。 必须在线程启动之前调用此方法。

到目前为止,使用setDaemon()是最容易的事情, 如果处理线程不需要在应用程序退出之前进行任何清理 (例如,它不需要完成或回滚原子提交事务),则建议使用setDaemon()


如果需要在线程退出之前对其进行清理,则最好不要将该线程设为守护程序,而应使该线程可中断,发出中断并处理该中断。

例如,使用ExecutorService管理线程,使用与ExecutorService javadoc中提到的方法类似的方法在Application stop()方法中关闭线程:

void shutdownAndAwaitTermination(ExecutorService pool) {
  pool.shutdown(); // Disable new tasks from being submitted
  try {
    // Wait a while for existing tasks to terminate
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
      pool.shutdownNow(); // Cancel currently executing tasks
      // Wait a while for tasks to respond to being cancelled
      if (!pool.awaitTermination(60, TimeUnit.SECONDS))
          System.err.println("Pool did not terminate");
    }
  } catch (InterruptedException ie) {
    // (Re-)Cancel if current thread also interrupted
    pool.shutdownNow();
    // Preserve interrupt status
    Thread.currentThread().interrupt();
  }
}

请注意, shutdownNow()调用将中断隐式发送到您的线程,除非将线程处理器显式编码为处理该中断,否则该中断将无效。

典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止。

如果取消确实没有用,而您只想放弃,则可以将上述代码中的System.err.println()语句替换为System.exit()

而且您的线程任务逻辑还需要处理中断:

public class PrimeProducer extends Thread {
    private final BlockingQueue<BigInteger> queue;

    PrimeProducer(BlockingQueue<BigInteger> queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            BigInteger p = BigInteger.ONE;
            while (!Thread.currentThread().isInterrupted())
                queue.put(p = p.nextProbablePrime());
        } catch (InterruptedException consumed) {
            /* Allow thread to exit */
        }
    }

    public void cancel() { interrupt(); }
}

另请注意,如果您不是子类化Thread,而是为库类型代码实现Runnable,则您不想像上面那样吞下中断,而是想恢复被中断的状态,类似于下面的内容(请阅读“下面的“处理InterruptedException”,以进一步了解为什么需要对库代码恢复中断状态):

public class TaskRunner implements Runnable {
    private BlockingQueue<Task> queue;

    public TaskRunner(BlockingQueue<Task> queue) { 
        this.queue = queue; 
    }

    public void run() { 
        try {
             while (true) {
                 Task task = queue.take(10, TimeUnit.SECONDS);
                 task.execute();
             }
         }
         catch (InterruptedException e) { 
             // Restore the interrupted status
             Thread.currentThread().interrupt();
         }
    }
}

另请参阅一些参考文档(从中复制并粘贴了此答案中的某些信息):

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM