Какой самый безопасный / лучший способ остановить поток и запустить некоторый код очистки
В рамках моих усилий по реализации программы распознавания голоса в 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); в любом случае, тогда, возможно, нет необходимости в чистом выходе из этого цикла... но это зависит от того, выполняете ли вы там другие операции очистки, такие как завершение записи в файлы и т. д.