How do I kill a Runnable running in a Thread?

Viewed 798

I have made a class called AbortableThread that is supposed to start and stop a thread when I want to. The class is relatively small since it just contains this code :

public class AbortableThread implements Runnable
{
    private Thread worker;
    private Runnable target;

    public AbortableThread(Runnable target)
    {
        this.target = target;
    }

    public void start()
    {
        worker = new Thread(this);
        worker.start();
    }

    public void stop()
    {
        worker.interrupt();
    }

    public void run()
    {
        while (!worker.isInterrupted())
            target.run();
    }
}

However, calling stop() does not stop the Thread. I think that's because target.run() runs on a separate thread, but I have no clue.

2 Answers

There isn’t a good way to stop a Runnable from outside (as a last resort there is stop, but that isn’t a good way). A Runnable needs to be a good citizen and check for interruption itself, using Thread.currentThread().isInterrupted(). If the Runnable catches InterruptedException, the interrupt flag will be cleared; the Runnable needs to restore the interrupt flag by calling interrupt on the current thread.

In the posted code what happens is that the Runnable executes on the worker thread and the worker never gets a chance to check the interruption flag until the Runnable completes. Assuming the Runnable is something like

() -> { try {
            Thread.sleep(100000L):
          } catch (InterruptedException e) {}}

then the sleep would be cut short when the worker is interrupted, but the interrupt flag would be cleared so the Runnable would be executed again in the next iteration of the loop.

Try something like this:

public class AbortableThread implements Runnable
{
    private final AtomicBoolean running = new AtomicBoolean(false);
    private Thread worker;
    private Runnable target;

    public AbortableThread(Runnable target)
    {
        this.target = target;
    }

    public void start()
    {
        worker = new Thread(this);
        worker.start();
    }

    public void stop()
    {
        running.set(false);
    }

    public void run()
    {
        running.set(true);
        while (running.get()) {
          try { 
            // make an small sleep
            Thread.sleep(1); 
          } catch (InterruptedException e){ 
            Thread.currentThread().interrupt();
            System.out.println(
              "Thread was interrupted, Failed to complete operation");
          }
          // do something here like the one in question; it must be none-blocking
          target.run();
       }
    }
 }

A complete example can be found here:

How to Kill a Java Thread

Related