Какой самый безопасный / лучший способ остановить поток и запустить некоторый код очистки

В рамках моих усилий по реализации программы распознавания голоса в Java, я реализовал реальный код распознавания голоса в отдельном потоке. Основной поток обрабатывает интерфейс GUI и получает постоянные обновления от потока распознавания голоса, когда слова идентифицированы.

Когда пользователь нажимает кнопку "Выйти" в графическом интерфейсе основного потока, я хочу, чтобы этот поток немедленно запустил некоторый код очистки и завершил работу.

В настоящее время у меня есть следующее:

public class VoiceRecognitionCore extends SwingWorker<List<String>, String>
{
    //Variables and things here

    @Override
    public List<String> doInBackground() throws VoiceRecognitionException
    {
        //Code here
        while(continueVoiceRecog == true)
        {
             //More code
             Result result = recog.recognize();
             //More code
        }
    }
}

Где я полагаюсь на цикл while, чтобы постоянно проверять состояние continueVoiceRecog, которое будет установлено в false основным потоком, когда пользователь нажимает "Выход".

Текущая проблема состоит в том, что код иногда может постоянно находиться внутри метода recog.recognize(), поэтому он никогда не вернется к проверке while. Следует отметить, что это всегда задумывалось как временное решение.

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

Какой самый безопасный / лучший подход для этого сценария? Если это то, что я предлагаю, есть ли потенциальные проблемы, о которых я должен знать?

1 ответ

Использование прерывания потока является вполне приемлемым маршрутом - однако в вашем примере (используя SwingWorker) вы можете использовать cancel() метод вместо.

В коде вызова после создания VoiceRecognitionCore вы можете cancel() слушатель действия кнопки выхода работника:

    final VoiceRecognitionCore worker = new VoicRecognitionCore();
    worker.execute();

    JButton exitButton = new JButton("Exit");
    exitButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            // True passed to Interrupt the underlying thread.
            worker.cancel(true);
            // other clean-up
            // then System.exit(0); ?
        }
    });

Тем не менее, этот подход должен проверить состояние: Thread.isInterrupted() в вашем recognize() метод. (см. ссылку: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/cancel.html)

Если вам нужно что-то почистить и у вас нет возможности проверить isInterrupted() флаг - возможно, лучший подход - иметь метод, позволяющий определить, recog объект находится в середине распознавания... и когда нажата кнопка выхода - если recog.isRecognizing() затем сделать уборку и затем выйти?

PS. Можно утверждать, что если вы делаете System.exit(0); в любом случае, тогда, возможно, нет необходимости в чистом выходе из этого цикла... но это зависит от того, выполняете ли вы там другие операции очистки, такие как завершение записи в файлы и т. д.

Другие вопросы по тегам