Matthew Matthew - 2 years ago 149
Java Question

Stop thread from other class

i'm trying to stop a specific

Thread
that implement
Runnable
.

I already try a few things that i found while googling it, but still can't find the best answer.

I have two
Class
.

1st is
Timer
. This class will create a countdown. It will send a result if
countdown == 0
to another class.

public class Timer implements Runnable {

public Timer(int countdown, Room room, String cmdName) {
this.room = room;
this.countdown = countdown;
this.cmdName = cmdName;
}

public void setResultThread(IResultThread resultThread) {
this.resultThread = resultThread;
}

@Override
public void run() {

for (int i = countdown; i >= 0; i--) {

countdown--;
if (i == 0) {
resultThread.setResult(true);
}

try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


2nd is
User
. I want to stop the
Thread
from this class.

Thread thread;
String threadName = "player-" + user.getName();
thread = utils.getThreadByName(threadName);

if (thread != null) {
thread.stop(); // i used stop before, but i read its not a good way
thread.interrupt();
}

if (nextTurn == 4) {
// do something
} else {

int countDown = 10
//getting player name

if (playerName != null) {
String newThreadName = "player-" + playerName;

Timer timer = new Timer(countDown, room, Send.PLAYER_TIMER.toString());
thread = new Thread(timer, newThreadName);
timer.setResultThread(resultThread);
thread.start();
}
}


I'm not sure if there's something wrong with my code or something.
I tried catch the exception, but the
Thread
countdown is still running. Its seems like its interrupt while the
Thread
is sleep. I ever tried with volatile boolean, but I don't think is a good way to approach in this case and of course its not working either.

I used
thread.stop()
before, but its not a good idea. This is the 1st time I'm using
Thread
, and its still a little bit confused for me.

I will appreciate any suggestion and answer. Thanks alot.




ANSWER



I put an answer just in case there's someone have a same problem with me.

@Override
public void run() {

try {
while (countdown >= 0) {

TimeUnit.MILLISECONDS.sleep(1000);
countdown--;
if (countdown == 0) {
resultThread.setResult(true);
}
}
} catch (InterruptedException e) {
countdown = 0;
Thread.currentThread().interrupt();
//e.printStackTrace();
}
}

Answer Source

There is no need to call Thread.stop().

The reason why your code doesn't currently stop when you interrupt the thread is that the handling of the interruption occurs inside the loop:

for (int i = countdown; i >= 0; i--) {
  // ...
  try {
    // Sleep
  } catch (InterruptedException e) {
  }
}

When the thread is interrupted during (or before) the sleep, the interruption is "swallowed": you handle it, so the loop just continues on to the next iteration, if any.

There's a Robin Williams skit about British police, who, owing to their lack of guns, have to say "Stop! Or.... I'll say stop again!". If you kept calling interrupt, eventually your thread would finish, because eventually the loop would execute the appropriate number of times. But this would be really messy, and is quite unnecessary.

Reverse the order of the loop and the try/catch:

try {
  for (int i = countdown; i >= 0; i--) {
    // ...

    // Sleep
  }
} catch (InterruptedException e) {
}

Now, when the interruption occurs, execution moves to after the loop, so no more loop iterations occur.

(Of course, you could leave your code as it is, and just return from the catch; but multiple return points can make the code harder to reason about)


You should also consider re-interrupting the current thread when you catch the InterruptedException:

// ...
} catch (InterruptedException e) {
  Thread.currentThread().interrupt();
}

This sets the interrupted flag on the current thread (confusingly, this is orthogonal to InterruptedException), allowing any code calling the Runnable to know that the thread was interrupted.

It's not strictly necessary to do this: if you know that the code is at the top of a thread's call stack (like here: there is no "caller" to be made aware of interruption). But re-interrupting the thread is nearly always the right thing to do (*), and doesn't actually hurt at all in this case.

(*) An example of when you wouldn't is if you are rethrowing the InterruptedException, or if you are writing threading framework code, and you know for sure it is the right thing not to.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download