0

eg:1

public class Test extends Thread {
    private Boolean stop = false;
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        test.start();
        TimeUnit.SECONDS.sleep(1);
        test.stop = true;
    }
    @Override
    public void run() {
        while (!this.stop) {
        }
        System.out.println("end");
    }
}

The code is written like this, and the thread will execute endlessly. However, add a little something to the while loop and change it to something like this:

eg:2

public class Test extends Thread {
    private Boolean stop = false;
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        test.start();
        TimeUnit.SECONDS.sleep(1);
        test.stop = true;
    }
    @Override
    public void run() {
        while (!this.stop) {
            System.out.println(1);  // Add some code
        }
        System.out.println("end");
    }
}

Q:

why is this happening? ??? Why can I interrupt it by printing a sentence, and it will not be interrupted without printing. . . . . . . . . . . . . . Note that stop is not added volatile. If added, it can be stopped after 1 second.

tomtom
  • 19
  • 2

1 Answers1

2

Because stop is not volatile, it is not guaranteed when a change in it made by one thread will be seen by another (unless something else provides that guarantee like a lock). So you will get unpredictable results.

There are a huge number of optimization that cannot be made if a change in an object made by one thread needs to be visible in another. But that is only a requirement for a very tiny fraction of realistic code. So the Java implementers wisely decided to make code that relies on that behavior indicate that and allow these significant optimizations to be made in the 99.5% of code that doesn't care about this.

If you want to rely on a change made in one thread being visible to another, you must use one of the mechanisms specified to provide this behavior. Otherwise, results are not guaranteed.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Why can I stop after 1 second by adding some code to `while` in `eg:2`? I suspect that the compiler is automatically optimized in `eg:1`, because `while` is empty, so the value of `stop` is only retrieved again. – tomtom May 28 '19 at 04:11
  • 2
    @tomtom As I explained, the results are unpredictable. No specific behavior is guaranteed. – David Schwartz May 28 '19 at 04:17
  • I would appreciate an explanation from the downvoter. If I am incorrect, I'd like to correct my misunderstanding. If I am unclear or incomplete, I'd like to know how it my answer could be improved. – David Schwartz May 28 '19 at 04:19
  • 1
    Didn't downvote, but it might be because you haven't properly answered the OP's question. You've explained what volatility is and why it's necessary in this case but haven't addressed why adding a `System.out.println(...)` statement seemingly affects the program's execution. – Slaw May 28 '19 at 07:05
  • @Slaw I did, it's because the results are unpredictable and therefore can't be predicted. – David Schwartz May 29 '19 at 01:31
  • Well, personally I find that a high level, abstract reason where I think the OP wanted to know specifically about `System.out.println(...)`. The duplicate gives a reason (for at least one JVM implementation). Note I actually upvoted. – Slaw May 29 '19 at 02:33
  • @Slaw Leading with a reason based on what happens to happen on one particular implementation is, IMO, a much worse way to answer a question like this. It leads to people thinking that when they can't think of any similar mechanism by which something could fail and it happens to work on their implementation, that means their code is okay. I've seen this exact scenario happen over and over. The most important thing to understand is that the behavior is unpredictable, even when you happen to guess right and can't think of any mechanism by which it could fail. – David Schwartz May 29 '19 at 13:51
  • Point conceded. – Slaw May 30 '19 at 07:51
  • @DavidSchwartz, it's an old thread, but it was me who downvoted the answer. The reason, as @Slaw suggested, is that you don't answer OP's question at all. He is aware that `volatile` is somehow needed, but wants to know what exactly happens right now. I think your motivation to not answer it is valid, but it's easy to overcome: just put what you have written in the comment to the answer. ... –  Jun 01 '19 at 16:06
  • @DavidSchwartz, Also, you are saying they are unpredictable, but it's not true: they ARE actually predictable to a certain extent, and such hints are priceless during debugging. I remember when I spent half a day trying to understand why my `List.add` (or something) resulted in an infinite loop, and my teamlead answered "concurrency" immediately after he heard about the issue. Answering the question may help one to figure out the general pattern, which they can recognize when something weird happens. –  Jun 01 '19 at 16:06
  • @dyukha I guess it's a judgment call. I've seen one particular pattern repeat so many times, and do so much damage, that I've decided to take fairly extreme measures to prevent it. Sure, maybe knowing what happens to happen sometimes on your platform helped you debug, but comparing that to the many times people who thought they knew what would happen released code they should have known was broken, I just can't see that tipping the scales. It is absolutely vital to know that there is no method to reliably predict what will happen, full stop. – David Schwartz Jun 01 '19 at 21:31