5

I am trying to run a for loop inside an infinite while loop. The code doesn't run as intended when there's no print statement, but when there is a print statement, it runs fine. Here is the code:

class Test implements Runnable{
  public static int varint = 0;
  public static void main(String args[]){
    Thread x = new Thread(new Test());
    int i;
    x.start();
    while(true){
      System.out.println("Hello World"); //If this isn't included, 
                                        //the exit statement isn't executed
      for(i=0;i<varint;i++){
        System.out.println("Exit");
        System.exit(0);
      }
    }
  }

  public void run(){
    try{
      Thread.sleep(5000);
    } catch(Exception e){
      System.out.println("Caught");
    }
    varint = 1;
  }
}

This is just a small example taken from a much bigger loop. How can I fix this?

2 Answers 2

7

You have a data race. One of the threads write to varint and the other reads varint with no explicit synchronization. varint is not declared volatile. According to Java memory model, there is no guarantee the reading thread will ever see the that varint was changed.

It works when you add the println because println uses synchronization internally, which makes varint visible to the running thread.

Either use a locking to read/write varint, or declare it volatile.

This is a good source for the Java memory model and volatiles:

http://tutorials.jenkov.com/java-concurrency/java-memory-model.html#visibility-of-shared-objects

Sign up to request clarification or add additional context in comments.

4 Comments

I've never heard of the volatile keyword. What exactly does it do?
It does a few things: read/writes to that variable include memory barriers. It also tells the compiler that another thread can modify it, so access to a volatile variable is not optimized to use a temp or a register.
Can you explain a bit more, or provide a link, for what in the Java memory model makes this so?
@JoshuaD, I added a link to the answer.
1

The main thread executing the loop in this avatar is not guaranteed to see any updates to varint. So varint can be updated to 1 or 100 but there would still be no guarantees for main thread to be able to see the updates.

In order to guarantee memory visibility, use a volatile or synchronization primitives.

Please see the following link from an architect of Java 5 Concurrency. This article explains: "Status Flags and Volatile"

On the other hand, the reading thread in certain cases (intermittently as in your case when you add the print) might see the update and it might seem the program is behaving correctly. Such kind of visibility issues are extremely hard to track if it makes it to production.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.