0

Given this code:

public class Game implements Runnable {
  private volatile boolean stop;

  public Game() {
    ...
  }

  public void run() {
    while(!stop) {
      // play game
    }
  }

  public void stopGame() {
    stop = true;
  }
}

public class Main {

  public static void main(String[] args){
    Game g = new Game(); // Game class implements Runnable
    Thread t = new Thread(g);
    t.start();
    // do the two method calls below effectively do the same thing?
    t.interrupt();
    g.stopGame(); 
  }

}

Does stopGame() kill the thread as effectively as using something like interrupt, or a java.lang.Thread method to kill the thread? (I'm not too familiar with how you would kill a thread using a Thread method.)

Also, in the case that stopGame() is the best way to kill a thread, is there any to call it if they only had access to the Thread instance like below:

public static void Main(String[] args){
  List<Thread> threads = new ArrayList<Thread>();
  threads.add(new Thread(new Game()));
  // can you access the Game instance given the Thread instance 
  // or do you need to hold onto the reference of the Game instance?
  threads.get(0).stopGame(); // for example, this won't work.
}
screeb
  • 625
  • 6
  • 20
  • What happens when you try it? Have you read the javadoc of interrupt()? – JB Nizet Apr 27 '17 at 20:36
  • I'm aware that you can use interrupt() to return from the run() function and kill the thread. I'm not particularly stressing just the use of interrupt here either, as there could be other methods of killing a Thread I'm unaware of. What I'm wondering is, if the stopGame() approach is the best, and if its just as effective as something like interrupt(). It just seems sort of strange as you're calling stopGame() on the instance of Game, whereas interrupt operates on the instance of Thread...will the Thread instance persist after using stopGame()? – screeb Apr 27 '17 at 20:42
  • A Thread is just a normal object. The Thread instance persists as long as it's reachable through a strong reference chain. If the thread does not run anymore because its runnable has returned, and if it's not referenced anywhere, it will be garbage collected. – JB Nizet Apr 28 '17 at 05:23

2 Answers2

4

Does stopGame() stop the thread as effectively as using something like interrupt, or a java.lang.Thread method to kill the thread? (I'm not too familiar with how you would kill a thread using a Thread method.)

The best way to stop a thread is to return from the run() method.

Your stopGame() call causes this on the next pass through the loop. But if that loop includes blocking calls, that next pass may occur after a delay -- or never.

Methods to kill the thread are deprecated because they're inherently unsafe.

Thread.interrupt() is not guaranteed to stop an arbitrary thread. It wakes up some blocking calls. It is common -- but not universal -- for a Runnable to stop when catching an InterruptedException. From the Java tutorial on interrupts:

An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate.

One approach is to both set a user-defined flag and call Thread.interrupt(). That will interrupt any blocking calls, and work even if code called by the Runnable has caught the InterruptedException or cleared the interrupt status flag.

Also, in the case that stopGame() is the best way to kill a thread, is there any to call it if they only had access to the Thread instance like below:

You could subclass Thread to hold a Game and provide a method in your subclass to stop the game. However, it's usually easier just to track the Runnable instances separately.

Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
  • I've a particular application where I'm running these games, and associating them with users, using a HashMap. In this case, would it be okay to declare a Thread, start it and then just keep the instance of Game in the HashMap, letting the reference to the thread be garbage collected and the thread to continue on, and perform any stops on the Game instance? – screeb Apr 27 '17 at 20:49
  • @bag - Okay, you're already holding onto your Game instances in the HashMap. Can you use the HashMap from users to Games to get the appropriate Game on which to call your method `Game.stopGame()`? – Andy Thomas Apr 27 '17 at 20:52
  • Yep, in this case I could go usersPlayingGames.get("bag").stopGame(), where usersPlayingGames is a HashMap. Is it alright to let the reference to the Thread be garbage collected, and only hold onto the Game instance? Or would the Thread also be garbage collected itself? – screeb Apr 27 '17 at 20:54
  • 1
    References are never garbage collected - they just go out of scope. The Thread object will not be collected until the thread has finished. You don't have to hold onto a reference to it. (If you're interested in the details of *why* a Thread object representing a thread will not be collected until the thread has finished, see [Java Thread Garbage collected or not](http://stackoverflow.com/questions/2423284/java-thread-garbage-collected-or-not). – Andy Thomas Apr 27 '17 at 20:57
  • One last thing - is it necessary for the boolean variable stop to be volatile when I want to be able to stop the thread from Main? – screeb Apr 27 '17 at 22:05
  • 1
    Yes, it would be a good idea to either make it volatile or use AtomicBoolean, to ensure the other thread actually sees the new value the next time it checks. If you don't make the operation atomic via one of these mechanisms, the other thread may see an older value of the variable. – Andy Thomas Apr 27 '17 at 22:23
  • I disagree that it's more effective than interrupt. Interrupting does basically the same thing, but **also** allows exiting from blocking methods such as wait(), sleep(), etc. In both cases, the thread needs to collaborate by checking the value of the interrupted/stop flag. – JB Nizet Apr 28 '17 at 05:19
  • @ Andy Thomas "Yes, it would be a good idea to either make it volatile or use AtomicBoolean, to ensure the other thread actually sees the new value the next time it checks" I think that the volatile modifier is enough for the use case. `AtomicBoolean` would have more sense if we also would need to synchronize the access to the boolean between 2 threads. Which is not the case here. Having the updated value of the boolean between the threads seems to be the single requirement. – davidxxx Apr 28 '17 at 06:13
  • @JBNizet - The two do different things. But you have a very good point that threads with blocking calls may *also* need an interrupt. Some Runnables will terminate on an interruption -- and others will not. An explicit flag on the Runnable will not be cleared by called code. Updated answer to cover Runnables with blocking code. – Andy Thomas Apr 28 '17 at 10:54
  • @AndyThomas I don't see the point of using two different mechanisms to stop a thread. Interrupting it is sufficient: if the code i currently blocked on a blocking call, it will get an InterruptedException. If it doesn't block or wants to stop at other times, all it needs to do is check the value of Thread.currentThread().isInterrupted(), just like it would check the value of the stop flag. The advantage is that you don't have the risk of forgetting to mak it volatile, and that you can check that value from anywhere in the call stack. – JB Nizet Apr 28 '17 at 13:00
  • @JB Nizet - I alluded to one point in the comment above, and in the answer. Another possible advantage would be some protection against accidental or malicious interruptions on the publicly accessible Thread object. Thank you again for raising the point about blocking calls. – Andy Thomas Apr 28 '17 at 15:18
0

"Killing" a thread is an abnormal situation.

The interrupt() method may do the job but in this case you don't need to use a boolean flag in the while condition of the run() method.
This :

  public void run() {
    while(!stop) {
      // play game
    }
  }

could be :

  public void run() {            
      while (!Thread.currentThread().isInterrupted()) {
         // play game
      }                
  }

But personally, I find it an aggressive way to stop the thread as any blocking call of the interrupted thread will be woken up.
You may so be forced to handle this premature exit that may create inconsistency while you are in a normal exit case.
Using a boolean flag lets the thread code be responsible of doing the job as it deems that it should be without forcing the exist of its blocking calls.

It doesn't mean that the InterruptedException should never be handled but I think that for a normal case (exit from user request), it makes no sense to make the code more complex as it is required.

Does stopGame() kill the thread as effectively as using something like interrupt, or a java.lang.Thread method to kill the thread?

The suitable way to end a thread is allowing it to terminate its execution : that is the run() of the method finishes its execution.

Using a boolean condition with a while as you are doing here is fine :

public void run() {
    while(!stop) {
      // play game
    }
  }

Also, in the case that stopGame() is the best way to kill a thread, is there any to call it if they only had access to the Thread instance like below:

You could do it for example :

  Game game = new Game(); 
  game.start();
  ...
  game.stopGame();
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • interrupt has nothing agressive and unpredictable. It's the preferred and well-documented way to ask a thread (or task) to stop running. – JB Nizet Apr 28 '17 at 05:20
  • From official documentation you can read that "an interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt." The thread may be working when it receives the interrupt request. So yes it may be agressive and it may also be unpredictable as you don`t know if it will be really interrupted. It s a technial flag, not a functional flag as the boolean stop that gives a clear way to finish the thread. – davidxxx Apr 28 '17 at 05:33
  • It's as unpredicatble as setting a stop flag: if the thread regularly checks for the flag and returns from the run method, it stops, otherwise, it doesn't. So it's exactly the same thing, **except** a stop flag does NOT allow to exit from a locking method such as sleep or wait, making it ineffective in that case. In both cases, it requires the collaboration of the thread to stop, and is not agressive at all. You're confusing interrupt() with stop(). – JB Nizet Apr 28 '17 at 05:37
  • I don't mix them. When you call interrupt(), as you have just said, you make the thread exit any blocking call. I find it aggressive because in the thread method that was interrupted, you may so be forced to handle this premature exit that may create inconsistency. Using a boolean flag lets the thread code be responsible of doing the job as it deems that it should be without waking its blocking call. – davidxxx Apr 28 '17 at 06:06
  • You're always forced to deal with "premature" exit, since any blocking interruptible method throws a checked InterruptedException, that the compiler forces you to handle, even if you don't plan to call interrupt. If you're ignoring InterruptedException, you're doing it wrong. – JB Nizet Apr 28 '17 at 06:14
  • @JB Nizet If you don't call interrupt, why write code that will not be executed in the **normal** state of the application such as solving consistency issues ? I find it is error prone and it is in a some way dead code. – davidxxx Apr 28 '17 at 06:17