2016-07-01 17 views
1

Я написал простое приложение JavaFX, которое, очевидно, работает в потоке приложений FX. Приложение нуждается в некоторой фоновой обработке в бесконечном цикле, работающем на отдельном потоке (не в потоке FX), где я вызываю Platform.runLater() для обновления элементов управления gui приложения FX через определенный интервал. Если я закрываю приложение FX Gui, фоновый поток продолжает его выполнение.Самый эффективный способ прервать Thread, если поток FX завершен в Java

Для того, чтобы прекратить фоновый поток после того, как FX нить кончилась, я теперь с помощью fxThread.isAlive() в цикле, а на фоновом потоке. Таким образом, фоновый поток автоматически завершается, как только поток потока прекращается, когда условие цикла while становится ложным.

Это плохой выбор? Каковы альтернативные и эффективные способы решения одной и той же задачи?

//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(); 

}

+0

Возможно, на вопрос http://codereview.stackexchange.com/ – ManoDestra

+0

, как вы завершаете приложение FX, и как вы запускаете фоновый поток? также я предполагаю, что вы не проходите мимо 'thread.setDaemon (true)' – AntJavaDev

+0

, пожалуйста, опубликуйте изменения в своем вопросе, а не в комментариях. – AntJavaDev

ответ

2

Называя fxThread.isAlive() это не совсем лучшее решение, потому что в худшем случае, ваш fxThread может умереть, в то время как поток прошел fxThread.isAlive() и в то время введя Platform.runLater даст вы исключение, за исключением случаев, когда это является надлежащим завершением для вашего дела.

попробуйте добавить слушателя для события закрытия на этапе верхнего уровня.

Также вызовите 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 
      } 
     } 
    } 

EDIT:

Согласно @ lostsoul29 комментарии, сценарий предполагает, что нерестовые потоки не будет демон темы. В случае, если какой-либо поток отмечен как демон, он потребует пользовательского завершения/обработки.

+0

Кажется, хорошо .... Не знал, что setOnCloseRequest() существует. Я только что добавил следующий фрагмент: primaryStage.setOnCloseRequest ((WindowEvent we) -> { System.exit (0); }); и обновил условие цикла while до «true» ... И он отлично работает. Thank you :) –

+0

'System.exit (0)' не убивает всех порожденных дочерних потоков. Вы должны по очереди закрыть каждый из потоков, а затем выйти из приложения. – lostsoul29

+0

@ lostsoul29, хорошо кажется, что вы не совсем поняли вопрос/ответ. В начале вы можете обратиться к ссылкам ниже, и если вы все еще сталкиваетесь с проблемами, сообщите нам об этом, задав новый вопрос. [Жизненный цикл потока] (https://docs.oracle.com/cd/E82638_01/JJDEV/threading-in-database.htm # JJDEV-GUID-44A07CEA-EB31-4C69-9300-6068A63EC880), [setDaemon()] (https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#setDaemon (boolean)) – AntJavaDev

2

Если нить не нужно делать каких-либо очистки по окончании, а затем просто сделать нить демон нить:

thread.setDaemon(true)

Marks этот поток или как демон нить или нить пользователя , Виртуальная машина Java выходит, когда единственными потоками, запущенными, являются все потоки демона. Этот метод должен быть вызван до начала потока.

Использование setDaemon() является самым простым, что нужно сделать, и это то, что рекомендуется если ваша обработка нити не нужно делать какие-либо очистки (например, не нужно заполнять или откат атомную совершить сделку) до выхода приложения.


Если вам необходимо выполнить очистку для потока перед выходом, то лучше не делать нить демон, но вместо того, чтобы сделать нить прерываемые, выдавать прерывания и обрабатывать прерывания.

Например, управлять нить с помощью ExecutorService, что вы выключение в методе Application stop() с использованием метода, аналогичной описанной в ExecutorService Javadoc:

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(); } 
} 

Также обратите внимание, если вы не подклассы темы, но вместо реализации 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(); 
     } 
    } 
} 

См. Также некоторые справочные документы (из которых некоторые из информации в этом ответе была скопировать и вставили):

+0

Это было довольно информативно. Спасибо большое :) –

 Смежные вопросы

  • Нет связанных вопросов^_^