Nico Giangregorio
Nico Giangregorio

Reputation: 105

Java, visibility and infinite loop occurrence

I'm studying Java Concurrency in Practice and there it is explained why the following snippet of code is bad:

public class NoVisibility {
    private static boolean ready;
    private static int number;
    private static class ReaderThread extends Thread {

      public void run() {
      while (!ready) {
        Thread.yield();
        System.out.println(number);
      }
    }

    public static void main(String[] args) {
       new ReaderThread().start();
       number = 42;
       ready = true;
   }
}

This code may print 0 or loop forever. While it is easy to understand why NoVisibility could print 0 instead of 42 (due to re-ordering issue), I'm a little confused about the infinite loop.

What is a practical scenario where an infinite loop may occurr, in this code?

Upvotes: 4

Views: 308

Answers (3)

veritas
veritas

Reputation: 2444

Please see the below code, It introduces the Infinite loop pretty on x86. Tried with jdk8 and jdk7

package com.snippets;


public class SharedVariable {

    private static int  sharedVariable = 0;// declare as volatile to make it work
    public static void main(String[] args) throws InterruptedException {

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                sharedVariable = 1;
            }
        }).start();

        for(int i=0;i<1000;i++) {
            for(;;) {
                if(sharedVariable == 1) {
                    break;
                }
            }
        }
        System.out.println("Value of SharedVariable : " + sharedVariable);
    }

}

Trick is not to expect the processor to do the reordering rather make compiler to make some optimization which introduces the visibility bug.

If you run the above code you will see it hangs indefinitely because it never sees the updated value sharedVariable.

To correct the code declare the sharedVariable as volatile.

Why normal variable didn't work and the above program hangs ?

  1. sharedVariable was not declared as volatile.
  2. Now because sharedVariable was not declared as volatile compiler optimizes the code. It sees that sharedVariable is not going be changed so why i should read from memory every time in the loop. It will take the sharedVariable out of the loop. Something similar to below.

    for(int i=0i<1000;i++)/**compiler reorders sharedVariable
    as it is not declared as volatile
    and takes out the if condition out of the loop
    which is valid as compiler figures out that it not gonna  
    change sharedVariable is not going change **/
      if(sharedVariable != 1) {  
        for(;;) {}  
      }      
    }
    

Shared at github : https://github.com/lazysun/concurrency/blob/master/Concurrency/src/com/snippets/SharedVariable.java

Upvotes: 0

alf
alf

Reputation: 8513

Well, it turns out that things are not nearly that easy: as you print in the cycle, you synchronize on the output streams, and that involves all the memory fences, so you will actually exit.

Now, you must not rely on such a behaviour, but that means if you're going to demonstrate the problem, you should be extra careful: many system calls, especially I/O, will involve hidden synchronization which can ruin a trick. So you end up saying, "that's baaaaad"— and being not able to prove that, which is a bit frustrating.

For a code example, check out illustrating volatile : is this code thread-safe? (sorry for a shameless plug—it's just that I only have this code there).

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 691943

The loop stops when ready is set to true. And ready is set to true by the main thread. But since the ready field is not volatile, the looping thread might continue to see a cached value: false.

The volatile keyword guarantees that all the threads reading a volatile field will actually see the last value stored in this field by any other thread. Without volatile, you don't have this guarantee.

Upvotes: 9

Related Questions