316

I need a solution to properly stop the thread in Java.

I have IndexProcessorclass which implements the Runnable interface:

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);

    @Override
    public void run() {
        boolean run = true;
        while (run) {
            try {
                LOGGER.debug("Sleeping...");
                Thread.sleep((long) 15000);

                LOGGER.debug("Processing");
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
                run = false;
            }
        }

    }
}

And I have ServletContextListener class which starts and stops the thread:

public class SearchEngineContextListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);

    private Thread thread = null;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        thread = new Thread(new IndexProcessor());
        LOGGER.debug("Starting thread: " + thread);
        thread.start();
        LOGGER.debug("Background process successfully started.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        LOGGER.debug("Stopping thread: " + thread);
        if (thread != null) {
            thread.interrupt();
            LOGGER.debug("Thread successfully stopped.");
        }
    }
}

But when I shutdown tomcat, I get the exception in my IndexProcessor class:

2012-06-09 17:04:50,671 [Thread-3] ERROR  IndexProcessor Exception
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at lt.ccl.searchengine.processor.IndexProcessor.run(IndexProcessor.java:22)
    at java.lang.Thread.run(Unknown Source)

I am using JDK 1.6. So the question is:

How can I stop the thread and not throw any exceptions?

P.S. I do not want to use .stop(); method because it is deprecated.

TryinHard
  • 4,078
  • 3
  • 28
  • 54
Paulius Matulionis
  • 23,085
  • 22
  • 103
  • 143
  • 1
    Terminating a thread half way will always generate an exception. If it is normal behavior, then you can just catch and ignore the `InterruptedException`. This is what I think, but I also wonder how the standard way is. – nhahtdh Jun 09 '12 at 14:18
  • I have not been using threads very often so I am pretty new at threads, so I do not know if it is normal behavior to ignore the exception. That is why I am asking. – Paulius Matulionis Jun 09 '12 at 14:23
  • In many cases it is normal behavior to ignore the exception and terminate the method processing. See my answer below for why this is bettern than a flag based approach. – Matt Jun 09 '12 at 16:29
  • 1
    A neat explanation by B. Goetz regarding `InterruptedException` can be found at http://www.ibm.com/developerworks/library/j-jtp05236/. – Daniel Dec 30 '14 at 19:33
  • the InterruptedException is not a problem, your only issue in the posted code is you shouldn't log it as an error, there's really not a compelling reason to log it as all except as debug just to demonstrate it happened in case you're interested. the selected answer is unfortunate because it does not allow for cutting short calls to calls such as sleep and wait. – Nathan Hughes Feb 13 '15 at 20:57

9 Answers9

337

Using Thread.interrupt() is a perfectly acceptable way of doing this. In fact, it's probably preferrable to a flag as suggested above. The reason being that if you're in an interruptable blocking call (like Thread.sleep or using java.nio Channel operations), you'll actually be able to break out of those right away.

If you use a flag, you have to wait for the blocking operation to finish and then you can check your flag. In some cases you have to do this anyway, such as using standard InputStream/OutputStream which are not interruptable.

In that case, when a thread is interrupted, it will not interrupt the IO, however, you can easily do this routinely in your code (and you should do this at strategic points where you can safely stop and cleanup)

if (Thread.currentThread().isInterrupted()) {
  // cleanup and stop execution
  // for example a break in a loop
}

Like I said, the main advantage to Thread.interrupt() is that you can immediately break out of interruptable calls, which you can't do with the flag approach.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Matt
  • 11,523
  • 2
  • 23
  • 33
  • 37
    +1 - Thread.interupt() is *definitely* preferable to implementing the same thing using an ad-hoc flag. – Stephen C Apr 06 '13 at 04:57
  • 2
    I also think that this the perfect and efficient way to do so. +1 – RoboAlex Apr 10 '13 at 15:27
  • 4
    There's a small typo in the code, Thread.currentThread() doesn't have the parenthesis. – Vlad V Dec 12 '13 at 00:13
  • 2
    Actually it is not preferable to using a flag because someone else which come in contact with the thread may do interrupt on it from somewhere else, causing it to stop and being very hard to debug. Always use a flag as well. – JohnyTex Jan 18 '16 at 08:10
  • 2
    In this specific case calling `interrupt()` might be ok, but in a lot of other cases it is not (for example if a resource needs to be closed). If anyone changes the inner working of the loop, you would have to remember to change `interrupt()` to the boolean way. I would go for the safe way from the beginning and use the flag. – m0skit0 Sep 23 '16 at 09:00
  • but interrupt does not destroy the thread, would that not result to memory leak? – oziomajnr Oct 27 '16 at 16:04
  • A problem for me is that: when Thread.interrupt() called, the thread is actually not started yet. – weidongxu Jul 02 '18 at 09:30
  • @JohnyTex I think you mean using `isInterrupted` as flag in while loop is not preferable cause code elsewhere could interrupt the thread. using a `running` flag can avoid this problem. right? I say this because I feel your statements have multiple conflicting interpretations. – Murphy Ng Aug 16 '18 at 13:10
  • FYI, calling Thread.isInterrupted() does not clear the interrupt. https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html#isInterrupted() Calling Thread.interrupted() DOES clear the interrupt. https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html#interrupted() – blackstrype Dec 08 '20 at 23:31
191

In the IndexProcessor class you need a way of setting a flag which informs the thread that it will need to terminate, similar to the variable run that you have used just in the class scope.

When you wish to stop the thread, you set this flag and call join() on the thread and wait for it to finish.

Make sure that the flag is thread safe by using a volatile variable or by using getter and setter methods which are synchronised with the variable being used as the flag.

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
    private volatile boolean running = true;

    public void terminate() {
        running = false;
    }

    @Override
    public void run() {
        while (running) {
            try {
                LOGGER.debug("Sleeping...");
                Thread.sleep((long) 15000);

                LOGGER.debug("Processing");
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
                running = false;
            }
        }

    }
}

Then in SearchEngineContextListener:

public class SearchEngineContextListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);

    private Thread thread = null;
    private IndexProcessor runnable = null;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        runnable = new IndexProcessor();
        thread = new Thread(runnable);
        LOGGER.debug("Starting thread: " + thread);
        thread.start();
        LOGGER.debug("Background process successfully started.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        LOGGER.debug("Stopping thread: " + thread);
        if (thread != null) {
            runnable.terminate();
            thread.join();
            LOGGER.debug("Thread successfully stopped.");
        }
    }
}
DrYap
  • 6,525
  • 2
  • 31
  • 54
  • 4
    I have done exactly the same as you gave the examples in your answer just before I have looked that you edited it. Great answer! Thank you, now everything works perfectly :) – Paulius Matulionis Jun 09 '12 at 14:39
  • 1
    What if the thread logic is complex and invokes a lot of methods of other classes? It is not possible to check boolean flag everywhere. What to do then? – Soteric Jun 09 '12 at 14:53
  • You would have to change the code design so that you build it in a way in which a signal to the Runnable will cause the thread to exit. Most uses do have this loop in the run method so there is not usually the problem. – DrYap Jun 09 '12 at 14:57
  • Excellent solution, this is exactly what I was looking for. Is there a minimum amount of time that the Thread should sleep for? I'm assuming that the Thread.sleep() is definitely needed here? – littleK Jan 31 '13 at 18:52
  • The sleep is just as an example to make the thread take some time. From what I gather from your question I think Thread.yield() is what you want, it stops the thread running continuously and gives some time back to the OS. – DrYap Jan 31 '13 at 19:32
  • 3
    What happens if the join() statement throws an InterruptedException? – benzaita Nov 19 '14 at 09:53
  • From the documentation for java.lang.Thread.join: `Waits for this thread to die.` That's not **nearly** the same thing as *stopping* the thread. – FuriousFolder Sep 16 '15 at 16:43
  • @FuriousFolder which is why you have the flag to tell the thread to die... Matt's answer below is the preferred (less ad hoc than mine) answer for this. – DrYap Sep 16 '15 at 16:46
  • My apologies; I misread your control `while` as `while(true)` instead of `while(running)` – FuriousFolder Sep 16 '15 at 17:09
  • 22
    Downvoted for spreading bad advice. the hand-rolled flag approach means the application has to wait around for the sleep to finish, where interruption would cut the sleep short. It would be easy to modify this to use Thread#interrupt. – Nathan Hughes Oct 09 '15 at 12:28
  • Doing `(long) 123` isn't needed. Just do `123L` or `123l` – Universal Electricity Oct 18 '15 at 12:54
  • Actually, you can't stop thread when It's on sleeping. After all, sleeping is done and the thread is stopped by the flag. – Slim_user71169 Feb 23 '16 at 02:15
  • If you need to stop all thread instances at once (without calling `terminate()` on each instance), you can change the `running` member and the `terminate()` method to `static` and this way, a single call to `IndexProcess.terminate()` will terminate all of them. – Jose Rui Santos Mar 24 '16 at 11:08
  • What is the purpose of volatile keyword in this answer if that boolean flag isn't being shared among threads? – Prudhvi Apr 18 '16 at 19:44
  • @prudhvi: the Boolean flag *is* being shared by 2 threads: one thread is created by *new Thread(runnable)*, the other thread is the thread calling into *ContextDestroy()*. – StvnBrkdll Jun 29 '16 at 16:10
  • correct me if I am wrong - thread.join() is done so that the calling thread - contextDestroyed() - waits until runnabe.terminate() is completed and only then proceeds to other instructions. – veritas Sep 15 '20 at 10:37
31

Simple answer: You can stop a thread INTERNALLY in one of two common ways:

  • The run method hits a return subroutine.
  • Run method finishes, and returns implicitly.

You can also stop threads EXTERNALLY:

  • Call system.exit (this kills your entire process)
  • Call the thread object's interrupt() method *
  • See if the thread has an implemented method that sounds like it would work (like kill() or stop())

*: The expectation is that this is supposed to stop a thread. However, what the thread actually does when this happens is entirely up to what the developer wrote when they created the thread implementation.

A common pattern you see with run method implementations is a while(boolean){}, where the boolean is typically something named isRunning, it's a member variable of its thread class, it's volatile, and typically accessible by other threads by a setter method of sorts, e.g. kill() { isRunnable=false; }. These subroutines are nice because they allow the thread to release any resources it holds before terminating.

ardila
  • 1,277
  • 1
  • 13
  • 24
hamsterofdark
  • 341
  • 3
  • 4
  • 4
    "These subroutines are nice because they allow the thread to release any resources it holds before terminating." I don't understand. You can perfectly well clean up a thread's held resources using the "official" interrupted status. Just check it using Thread.currentThread().isInterrupted() or Thread.interrupted() (whichever fits your need), or catch the InterruptedException, and cleanup. Where's the problem? – Franz D. Aug 19 '18 at 19:29
  • I was not able to understand why the flag method works, because i hadnt understood that it stops when the run hits return!!! This was so simple,dear sir thank you for pointing this out, nobody had done this explicitly. – thahgr Jan 02 '19 at 14:51
10

You should always end threads by checking a flag in the run() loop (if any).

Your thread should look like this:

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
    private volatile boolean execute;

    @Override
    public void run() {
        this.execute = true;
        while (this.execute) {
            try {
                LOGGER.debug("Sleeping...");
                Thread.sleep((long) 15000);

                LOGGER.debug("Processing");
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
                this.execute = false;
            }
        }
    }

    public void stopExecuting() {
        this.execute = false;
    }
}

Then you can end the thread by calling thread.stopExecuting(). That way the thread is ended clean, but this takes up to 15 seconds (due to your sleep). You can still call thread.interrupt() if it's really urgent - but the prefered way should always be checking the flag.

To avoid waiting for 15 seconds, you can split up the sleep like this:

        ...
        try {
            LOGGER.debug("Sleeping...");
            for (int i = 0; (i < 150) && this.execute; i++) {
                Thread.sleep((long) 100);
            }

            LOGGER.debug("Processing");
        } catch (InterruptedException e) {
        ...
Chris
  • 3,113
  • 26
  • 33
  • 2
    it's not a `Thread` -- it implements `Runnable` -- you can't call `Thread` methods on it unless you declare it in as a `Thread` in which case you can't call `stopExecuting()` – Don Cheadle Dec 15 '14 at 20:07
8

Typically, a thread is terminated when it's interrupted. So, why not use the native boolean? Try isInterrupted():

Thread t = new Thread(new Runnable(){
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()){
                // do stuff         
            }   
        }});
    t.start();

    // Sleep a second, and then interrupt
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {}
    t.interrupt();

ref- How can I kill a thread? without using stop();

Lovekush Vishwakarma
  • 3,035
  • 23
  • 25
  • The interrupted thread **IS NOT** terminated, it's just interrupted. If the thread is interrupted while in `sleep()`, then it throws `InterruptedException` which your thread should catch and possibly end itself or maybe simply go on with further processing. `isInterrutped` will be `true` **ONLY** if the thread was not in `sleep` or `wait` (it was actually running) and this can give you a hint, that the thread was interrupted. In other words: if you put `sleep()` in your `// do stuff` line, then `t.interrupt()` won't terminate it (well, for 99.9% it won't). – Cromax Jun 29 '20 at 22:40
  • The first sentence of the answer should say "Typically, the goal of interruption is to terminate a thread." To clarify what @Cromax said, if this `while` condition is going to be the sole way to stop the thread, then any `catch (InterruptedException)` block needs to call `Thread.currentThread().interrupt();` in order to maintain the interrupted status for the `while` condition. But depending on the work, it might be safe to use those `catch` blocks to `break;` out of the loop early, or even safe to add more `.isInterrupted()` checks throughout the loop body. – AndrewF Feb 26 '21 at 06:10
  • "Blocking library methods like Thread.sleep and Object.wait try to detect when a thread has been interrupted and return early. They respond to interruption by clearing the interrupted status and throwing InterruptedException, indicating that the blocking operation completed early due to interruption. The JVM makes no guarantees on how quickly a blocking method will detect inter- ruption, but in practice this happens reasonably quickly." Brian Goetz – Eugene Maysyuk Nov 12 '22 at 22:48
5

For synchronizing threads I prefer using CountDownLatch which helps threads to wait until the process being performed complete. In this case, the worker class is set up with a CountDownLatch instance with a given count. A call to await method will block until the current count reaches zero due to invocations of the countDown method or the timeout set is reached. This approach allows interrupting a thread instantly without having to wait for the specified waiting time to elapse:

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);

    private final CountDownLatch countdownlatch;
    public IndexProcessor(CountDownLatch countdownlatch) {
        this.countdownlatch = countdownlatch;
    }


    public void run() {
        try {
            while (!countdownlatch.await(15000, TimeUnit.MILLISECONDS)) {
                LOGGER.debug("Processing...");
            }
        } catch (InterruptedException e) {
            LOGGER.error("Exception", e);
            run = false;
        }

    }
}

When you want to finish execution of the other thread, execute countDown on the CountDownLatch and join the thread to the main thread:

public class SearchEngineContextListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);

    private Thread thread = null;
    private IndexProcessor runnable = null;
    private CountDownLatch countdownLatch = null;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        countdownLatch = new CountDownLatch(1);
        Thread thread = new Thread(new IndexProcessor(countdownLatch));
        LOGGER.debug("Starting thread: " + thread);
        thread.start();
        LOGGER.debug("Background process successfully started.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        LOGGER.debug("Stopping thread: " + thread);
        if (countdownLatch != null) 
        {
            countdownLatch.countDown();
        } 
        if (thread != null) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
            }
            LOGGER.debug("Thread successfully stopped.");
        } 
    }
}
Eduardo Sanchez-Ros
  • 1,777
  • 2
  • 18
  • 30
3

Some supplementary info. Both flag and interrupt are suggested in the Java doc.

https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

private volatile Thread blinker;

public void stop() {
    blinker = null;
}

public void run() {
    Thread thisThread = Thread.currentThread();
    while (blinker == thisThread) {
        try {
            Thread.sleep(interval);
        } catch (InterruptedException e){
        }
        repaint();
    }
}

For a thread that waits for long periods (e.g., for input), use Thread.interrupt

public void stop() {
     Thread moribund = waiter;
      waiter = null;
      moribund.interrupt();
 }
Feng
  • 39
  • 1
  • 3
  • 3
    Never ignore an InterruptedException. It means some other code is explicitly asking your thread to terminate. A thread which ignores that request is a rogue thread. The correct way to handle an InterruptedException is to exit the loop. – VGR Mar 21 '18 at 19:54
2

I didn't get the interrupt to work in Android, so I used this method, works perfectly:

boolean shouldCheckUpdates = true;

private void startupCheckForUpdatesEveryFewSeconds() {
    threadCheckChat = new Thread(new CheckUpdates());
    threadCheckChat.start();
}

private class CheckUpdates implements Runnable{
    public void run() {
        while (shouldCheckUpdates){
            System.out.println("Do your thing here");
        }
    }
}

 public void stop(){
        shouldCheckUpdates = false;
 }
Mindborg
  • 73
  • 3
1

Brian Goetz in his book suggests to use Thread.currentThread().isInterrupted() flag and interrupt() method for cancellation.

Blocking library methods like sleep() and wait() try to detect when a thread has been interrupted and return early. They respond to interruption by clearing the interrupted status and throwing InterruptedException, indicating that the blocking operation completed early due to interruption.

The JVM makes no guarantees on how quickly a blocking method will detect interruption, but in practice this happens reasonably quickly.

class PrimeProducer extends Thread {
    private final BlockingQueue<BigInteger> queue;

    PrimeProducer(BlockingQueue<BigInteger> queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            BigInteger p = BigInteger.ONE;
            while (!Thread.currentThread().isInterrupted()) {
                queue.put(p = p.nextProbablePrime()); // blocking operation
            }
        } catch (InterruptedException consumed) {
            // allow thread to exit
        }
        // any code here will still be executed
    }

    public void cancel() {
        interrupt();
    }
}

If you put any code after catch block, it will still be executed as we swallow InterruptedException to exit from run() gracefully.

Just a couple words on how interrupt() works.

If interrupt is called on non-blocked thread, interrupt() will not cause InterruptedException inside run() but will just change flag isInterrupted to true and thread will continue its work until it reaches Thread.currentThread().isInterrupted() check and exit from run().

If interrupt is called on blocked thread (sleep() or wait()was called, in our case it's put() that might block a thread) then isInterrupted will be set to false and InterruptedException will be thrown inside put().

Eugene Maysyuk
  • 2,977
  • 25
  • 24