4

I am writing a GUI for a program that takes some inputs and runs an algorithm on them. The code for the algorithm is fairly long and complex so I have just been launching a new thread from the GUI in order to perform the computations on the inputs.

//algorithmThread previously initialized 
 if(e.getSource() == startButton) {
        if(update.updateStrings(textFields)) {
            algorithmThread.start();  
        }
    }

We want to add functionality that will allow the user to stop the computation (it runs for about half an hour on my laptop before producing a result) in the case that they have provided the wrong input files. This is how I am handling that.

 else if(e.getSource() == stopButton) {
        //if the user presses the stop button then intterupt the 
        //thread running the algorithm
        algorithmThread.interrupt();
        System.out.println("algorithm stopped"); //debugging code
        //recreate the thread in case the user hits the start button again
        algorithmThread = new Thread() {
                public void run() {
                    runNOC();
                }
            };
    }

The program does successfully stop the algorithm(although I think I should do some exception handling), allow the user to enter new input, and restart. My question is, under what conditions would I have to check Thread.interrupted() in the code for the algorithm? Is it necessary/best practice? Or is it acceptable to stop a thread in the manner illustrated above?

  • [this link](http://arashmd.blogspot.com/2013/06/java-threading.html#shuttr) would help you out –  Sep 29 '13 at 16:56
  • Your approach is fine. How often you check the interrupted flag will be directly linked to how long it takes for your thread to stop its job once the user has clicked on the "stop" button... – assylias Sep 29 '13 at 18:30

2 Answers2

4

All the Thread.interrupt() method does is set an "interrupted" flag, so stopping a thread in this manner requires its cooperation. For example, the algorithm should poll the interrupt status every once in a while, for example once per iteration. You can see an example of this in the Java concurrency tutorial.

Since you are working with a GUI, you may find it easier to run the background thread using a SwingWorker. This class has many features convenient for GUI programming, like updating the GUI when the computation has finished using the done method and canceling the computation without using Thread.interrupt(). Canceling in this manner still requires cooperation from the thread, but is safer because interrupting a thread causes an InterruptedException to be thrown in some situations, such as when the thread is sleeping in Thread.sleep or waiting on a lock in Object.wait.

Joni
  • 108,737
  • 14
  • 143
  • 193
  • 1
    It only causes an `InterruptedException` if the thread is doing something that can be interrupted, such as sleeping or waiting. In a normal state of execution only the flag is set. – Joni Sep 29 '13 at 17:05
  • @val What exactly does the Javadoc say? – pburka Sep 29 '13 at 17:07
  • It says exactly that the first edit of Joni post was misinformation. – Val Sep 29 '13 at 17:10
  • Okay. So I guess that answer is yes I do have to check the "interrupted" flag in the thread performing the computations. I guess that leads me to another question. Why is the thread terminating after I call algorithmThread.interrupt() although I am not checking thread.interrupted() == true in the algorithmThread? – user2828777 Sep 29 '13 at 17:24
  • How do you verify the thread was terminated? Was an exception thrown? – Joni Sep 29 '13 at 17:34
  • I am examining it in the debugger. When I hit the start button Thread 1 is created and when I hit the stop button Thread 1 disappears. It throws a java.lang.InterruptedException. I guess if I check the interrupted flag then this exception will not be thrown? – user2828777 Sep 29 '13 at 17:47
  • Yes, some API methods check the flag and throw an `InterruptedException`. Which method threw it, you have the stack trace? Most of the methods that do this are related to waiting for a resource or condition, so it's really surprising to see this happening with something that's pure computation. – Joni Sep 29 '13 at 17:52
  • 1
    SEVERE: null java.lang.InterruptedException at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:996) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1303) at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:248) at java.util.concurrent.FutureTask.get(FutureTask.java:111) at java.util.concurrent.AbstractExecutorService.invokeAll(AbstractExecutorService.java:243) – user2828777 Sep 29 '13 at 18:14
  • at nocit_new_run1.NOCAlgorithm.run(NOCIt_new_run1.java:143) at nocit_new_run1.InputUI.runNOC(InputUI.java:279) at nocit_new_run1.InputUI$1.run(InputUI.java:81) Sorry the formatting is so horrible – user2828777 Sep 29 '13 at 18:16
  • Now. The algorithm does a lot of I/O on CSV files. Could that through an InterruptedException? – user2828777 Sep 29 '13 at 18:22
  • Your algorithm thread runs another thread to do the computation and waits for its results. When you interrupt the algorithm thread you interrupt the wait, but the computation that was already running continues until the end. – Joni Sep 29 '13 at 18:23
  • Thanks for your help. I will work with the person who provided the code and we will have to determine some areas to check the interrupted flag – user2828777 Sep 29 '13 at 18:47
  • You are using `ExecutorService.invokeAll`. When you interrupt it, the tasks that are scheduled for execution but haven't started are canceled. If the tasks are sufficiently small this is enough to consider the entire computation as canceled and you don't need to do anything more, but if each task takes more than 10 seconds to complete you may want to handle the exception in the algorithm thread [as shown in the `ExecutorService` documentation](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html). – Joni Sep 29 '13 at 18:48
0

interrupt is not always evil following this thread: Is Thread.interrupt() evil?

Around here, we use this method in one specific place: handling InterruptedExceptions. That may seem a little strange but here's what it looks like in code:

try {
     // Some code that might throw an InterruptedException.  
     // Using sleep as an example
     Thread.sleep(10000); 
     } 
catch (InterruptedException ie) {
     System.err.println("Interrupted in our long run.  Stopping.");
     Thread.currentThread().interrupt(); 
     } 

This does two things for us:

  1. It avoids eating the interrupt exception. IDE auto-exception handlers always provide you with something like ie.printStackTrace(); and a jaunty "TODO: Something useful needs to go here!" comment.

  2. It restores the interrupt status without forcing a checked exception on this method. If the method signature that you're implementing does not have a throws InterruptedException clause, this is your other option for propagating that interrupted status.

Community
  • 1
  • 1
kiriloff
  • 25,609
  • 37
  • 148
  • 229