0

To my understanding the following code should terminate normally as the condition stopRunning = true; is met.

However, when I run this program it is printing only Last line of Main(), Start Method ended is never printed as the while loop is never terminated.

 public class Test {
     private static boolean stopRunning = false;
     public static void main(String[] args) throws Exception {
        new Thread(new Runnable() {

            @Override
            public void run() {
                start();
            }

        }).start();

        Thread.sleep(100);
        stopRunning = true;
        System.out.println("Last line of Main()");
    }
    public static void start() {
        while (!stopRunning) {

        }
        System.out.println("Start Method ended.");
    }
}

Please help me understand this behavior.

bugfreerammohan
  • 1,471
  • 1
  • 7
  • 22
T-Bag
  • 10,916
  • 3
  • 54
  • 118
  • 1
    Add another sleep after `System.out.println("Last line of Main()");` – Antoniossss Aug 01 '18 at 11:10
  • add larger interval in `Thread.sleep(100);` like `Thread.sleep(2000);` – rt2800 Aug 01 '18 at 11:12
  • 1
    @rt2800 would give exact same result. – Antoniossss Aug 01 '18 at 11:13
  • ~~```start();``` rename that (within your ```run```) to ```Test.start()```. I´m pretty sure you´re never even calling the ```start``` you think you are calling.~~ Or, wait actually I didn´t see it was runnable and not Thread you extended from. – Max Aug 01 '18 at 11:17

3 Answers3

1

Changing the flag to volatile with

private static volatile boolean stopRunning = false;

will mean that other threads see the change immediately (from main memory instead of a cache), and the code executes as you expect. How volatile relates to Java's memory model is explained further e.g. in this tutorial.

Mick Mnemonic
  • 7,808
  • 2
  • 26
  • 30
0

As Mick stated, you should use the volatile keyword to synchronize your variable, so on a change the new value is written directly back to memory and your code will work as expected.

Be aware (also stated in the article Mick linked) that volatile does not guarantee to avoid race conditions, so if two different threads would read your variable, it is not safe that they both read the same value (despite everything is read from memory and on change directly written back)

ItFreak
  • 2,299
  • 5
  • 21
  • 45
0

As stated in previous answers:

  1. Like Mike stated - in run() you should use Test.start() or rename the method. The start you are calling is the thread's start method.
  2. Also as Mick stated, setting stopRunning as volatile should help. The reason it should work is that it will remove the caching of the variable in the thread's memory and will get/set directly from memory.
Galg
  • 17
  • 5
  • 1) really ? how? it is a Runnable, it is not a subclass of the thread, it is a nested class of Test, that is, will search `start` of Runnable and then of Test (i agree it is not a good style, but only that) - changing the variable to `volatile` is enough – user85421 Aug 01 '18 at 11:29
  • the main reason to avoid `start` - it is just too confusing – user85421 Aug 01 '18 at 11:58