0

As part of my efforts to implement a voice recognition program in Java I have implemented the actual voice recognition code in a separate thread. The main thread handles the GUI interface and receives constant updates from the voice recognition thread when words are identified.

When the user clicks the Quit button in the GUI on the main thread I want this thread to immediately run some clean-up code and terminate.

I currently have the following:

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
        }
    }
}

Where I rely on the while loop to constantly check the status of continueVoiceRecog which will be set to false by the main thread when the user clicks "Quit".

The current problem is that the code can sometimes permanently sit inside the recog.recognize() method so it'll never get back to the while check. It should be noted that this was always intended as a temporary solution.

I'm thinking of extending doInBackground() to catch InterruptedException and will use a thread interrupt which will call a cleanup method to deallocate any resources being used.

What is the safest/best approach for this scenario? If it is what I propose, are there any potential issues I should be aware of?

H0rizon
  • 53
  • 6

1 Answers1

1

Using thread interrupt is perfectly acceptable route - however in your example (using SwingWorker) you can use the cancel() method instead.

In the calling code after having created the VoiceRecognitionCore you can cancel() the worker exit button action listener:

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

However, this approach will need to check the status of: Thread.isInterrupted() within your recognize() method. (see link: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/cancel.html)

If you are needing to clean-up stuff and don't have ability to check the isInterrupted() flag - perhaps best approach is to have a method to be able to determine if your recog object is mid recognizing... and when the exit button is pressed - if recog.isRecognizing() then do clean up and then exit?

PS. One might argue that if you are doing a System.exit(0); anyway, then cleanly exiting that loop is perhaps unnecessary ... but it depends if you are doing other clean-up in there... such as finishing writing to files etc.