5

I change a value that is used to determine when a while-loop terminates in a seperate thread.
I don't want to know how to get this working. If I access the variable test only through synchronized getters/setters it works as expected..

I would have expected, if some read/write commands are lost due to concurrency the program sometimes does not terminate, but it never does. Thats what confuses me..
I would like to know why the program never terminates, without the print-command. And I would like to understand why the print-command changes anything..

     

    public class CustomComboBoxDemo  {
        public static boolean test = true;
        public static void main(String[] args) {
            Thread user =new Thread(){
                @Override
                public void run(){
                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {}
                    test=false;
                }
            };
            user.start();
            while(test) {
                System.out.println("foo"); //Without this line the program does not terminate..
            }
        }
    }

Heinrich Ody
  • 289
  • 2
  • 9
  • See: [Loop doesn't see changed value without a print statement](https://stackoverflow.com/questions/25425130/loop-doesnt-see-changed-value-without-a-print-statement) – Boann Jan 16 '15 at 22:35

6 Answers6

8

The most likely explanation is that the variable is only read once, turning the while into an infinite loop (or a no-op). Since you haven't declared test as volatile, the compiler is allowed to perform such an optimization.

Once you call an external function from within the loop, the compiler can no longer prove that test remains invariant across loop iterations, and doesn't perform the optimization.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
1

If the test variable is not defined as volatile, the compiler probably optimizes the loop containing no operation into a while(true) loop for your main thread and the program never ends.

Otherwise, the value of the test variable is actually checked and when your second thread changes its value, then the main thread leaves the while loop and your program terminates.

Jean Logeart
  • 52,687
  • 11
  • 83
  • 118
0

I presume it's something to do with the way IO is handled. Without the print, you'll probably see the java application using all available CPU time; with the print it's likely that IO delays give up enough CPU time for other processing to take place.

A quick way to test this theory would be to put printlns in the run() method of your thread to see whether the thread is actually ever executing. In my experience, infinite empty loops cause a lot of strange behaviour.

That said, it appears to terminate fine on my workstation under JDK 1.6.0_10_b23

mcfinnigan
  • 11,442
  • 35
  • 28
  • Agree with mcfinnigan. Add some debugging prints to your thread. When something doesn't work as expected, always do some work to prove that your assumptions are correct, in this case that the separate thread is working as designed. – Mitch Jan 05 '12 at 14:27
0

Seems like your loop is being incorrectly compiled away into a busy-wait. Adding a volatile keyword to your boolean corrects the 'problem'.

Perception
  • 79,279
  • 19
  • 185
  • 195
0
public static boolean test = true;
public static void main(String[] args) {
    Thread user =new Thread(){
        @Override
        public void run(){
            try {
                sleep(2000);
            } catch (InterruptedException e) {}
            test=false;
            System.out.println("Thread.end <"+test+">");
        }
    };
    user.start();
    while(test);
}

That's interesting. The compiler most probably optimzes this while into an endless loop, not reading the value at each loop.

Defining test as volatile fixes this and let your program terminate

Btw: you probably already know that you shoud use user.join() to wait for the Thread to end

Community
  • 1
  • 1
Hons
  • 3,804
  • 3
  • 32
  • 50
0

I don't understand what you are trying to do by using code you know is not correctly synchronized.

As some have reported, on their machine the code behaves differently than on your machine. The behavior of badly synchronized code is undefined. It makes no sense to try to understand what it does since that behavior will change with the JVM version or architecture.

toto2
  • 5,306
  • 21
  • 24