0

All answers are about how to stop loop of some thread, but what if I don't have a loop but I still want to stop a thread before it executes/processes all lines?

For example I have a thread which usually runs for 7-10 seconds and then dies (terminates):

mThread = new Thread(new Runnable() {
   @Override
   public void run() {

    // some code here 
    // some here  
    // some here
    // some here          
    // some here
    // all lines takes about 7-10 seconds

   }
});

If I started a thread and after 2 or 3 seconds I need to stop it, then how to do it and don't wait 10 seconds?

user25
  • 2,873
  • 2
  • 30
  • 66
  • 1
    If your thread is in a blocking call, call interrupt. This is the preffered way in java to cancel IO and blocking calls. – Jazzwave06 Mar 23 '18 at 12:41
  • Do you know from inside the `run` method that you need to stop processing? – Alexandre Dupriez Mar 23 '18 at 12:41
  • Possible duplicate of [How do you kill a thread in Java?](https://stackoverflow.com/questions/671049/how-do-you-kill-a-thread-in-java) – FazoM Mar 23 '18 at 12:42
  • @FazoM there they talk about `while` – user25 Mar 23 '18 at 12:42
  • 2
    Create a flag and check it before doing something. You can't guarantee immediate interruption in a multithreaded environment. – Ben Mar 23 '18 at 12:43
  • @user25 I don't see any mention of `while` in the linked question. Anyway, good look with solving your problem – FazoM Mar 23 '18 at 16:45
  • @FazoM most answers there about how to stop `while` (though author didn't mention it, he just asked a short general question, I asked a more specific question because I know it's not easy to stop/kill and .stop method is deprecated), and no answers like I got in my question https://stackoverflow.com/a/49450107/4548520 – user25 Mar 23 '18 at 18:16

4 Answers4

3

If your thread is not blocked, and is actually processing stuff, then interrupting it might not help. You can code the thread to check for the interrupt flag on the current thread and then stop if it sees that the flag has been set.

This is how you check to see if the current thread has been interrupted.

Thread.currentThread().isInterrupted();

So you would have to code your thread like this...

mThread = new Thread(new Runnable() {
   @Override
   public void run() {

    // some code here 
    if (Thread.currentThread().isInterrupted()) return;
    // some here  
    if (Thread.currentThread().isInterrupted()) return;
    // some here
    if (Thread.currentThread().isInterrupted()) return;
    // some here          
    if (Thread.currentThread().isInterrupted()) return;
    // some here
    // all lines takes about 7-10 seconds    
   }
});

Then you can go ahead and interrupt the mThread and it will have an effect. Though it will still continue processing the current some here step it is on.

Jose Martinez
  • 11,452
  • 7
  • 53
  • 68
  • this is what I don't like to put conditions before every line :) and also it still be waiting some lines to finish, what about to interrupt while one line is still executed? – user25 Mar 23 '18 at 12:54
  • but I guess it's the only way – user25 Mar 23 '18 at 12:55
  • If the line is blocked, then the interrupt will stop the execution of that line. It really comes down to weather or not the code being interrupted is interruptible. No way around that. A lot of good JDK code will check to see if it is interrupted before continuing processing. – Jose Martinez Mar 23 '18 at 12:56
  • Just note that in general, `interrupt` is not meant for **stopping** a thread. It's mainly used for interrupting a `sleep` or other **idle periods**, not necessarily to stop the thread. – Zabuzard Mar 23 '18 at 13:10
3

Explanation

The preferred way is to implement a stopping mechanism in the thread. You can also try to observe the interrupt flag. You can interrupt from outside using the Thread#interrupt method and the thread can check the flag using Thread#isInterrupted and Thread#interrupted (see documentation of Thread).

There is no way to force a thread from outside to stop without the thread actually implementing the logic by itself. There is the Thread#stop method but it is deprecated and should never be used. From its documentation:

Deprecated. This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait. For more information, see Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?.


Solution

You could modify the thread like this:

public class MyThread implements Runnable {
    private volatile boolean mShouldStop = false;

    public void shutdown() {
        mShouldStop = true;
    }

    @Override
    public void run() {
        // First line ...
        if (mShouldStop) return;
        // Second line ...
        if (mShouldStop) return;
        // Third line ...
        if (mShouldStop) return;
    }
}

So you need to periodically check the flag and then manually abort.

Usually such threads have some kind of while (true) loop. In this case it gets easier, you could do:

@Override
public void run() {
    while (!mShouldStop) {
        // Do something ...
    }
}

Depending on your application you might interpret the interruption flag as signal for a thread shutdown. Then your code could look like

@Override
public void run() {
    while (!Thread.interrupted()) {
        // Do something ...
    }
}

Note

The mShouldStop needs to be volatile to ensure it is updated correctly for the Thread. See the tutorial by Oracle for Atomic Access.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • I think you need to mark that `boolean` as `volatile` – paulturnip Mar 23 '18 at 13:00
  • 1
    or without using `boolean` but `isInterrupted` like here I guess would be a little better `https://stackoverflow.com/a/49450107/4548520 – user25 Mar 23 '18 at 13:04
  • Yup. It depends. Sometimes you want the *interruption flag* to have a different meaning. Like only a notification from outside "*hey, something has changed, please check*". So it can be part of a regular logic instead. Especially if the thread `sleep`s regularly, then this can be used to interrupt the sleep. – Zabuzard Mar 23 '18 at 13:06
  • If one of the steps is blocked, just setting the `mShouldStop` won't stop it. You still have to interrupt the thread. Interrupting will ensure that any blocking steps get stopped. The flag is nice but the `isInterrupted` is just as good and will capture situations where your thread was attempted to be stopped from code that was not specifically coded to set your `mShouldStop` flag. Hence, IMHO, using `isInterrupted` as your flag is a more full proof way to stop the thread. – Jose Martinez Mar 23 '18 at 13:31
0

You interrupt the thread with mThread.interrupt(). But, for this to work, your thread needs to check the interrupt status (by sleeping). Check out this thread.

For more details, refer this thread.

Pankaj Singhal
  • 15,283
  • 9
  • 47
  • 86
0

You need to check the interrupt status in your thread. Something like this

import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class ThreadInterruptor {


    private static class Worker implements Runnable {
        @Override
        public void run() {
            while (true) {
                IntStream.range(0, Short.MAX_VALUE).forEach(i ->noop());
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("i got interrupted");
                    break;
                }
            }
        }
        private void noop(){}
    }


    public static void main(String[] args) throws Exception{
        Thread thread = new Thread(new Worker());
        thread.start();
        TimeUnit.SECONDS.sleep(5);
        thread.interrupt();
    }

}
paulturnip
  • 106
  • 5