3

I have two threads and in one thread I set static variable and in another I check static variable via function like this

Test test= new Test();
while(!Temp.isVarSet()){
}
System.out.println("Variable set");

But this codes hangs - doesn't go to println statement. But the following code works

Test test= new Test();
while(!Temp.isVarSet()){
  System.out.println("I am still here");
}
System.out.println("Variable set");

The Temp class

public class Temp {

    private volatile static boolean varSet=false;

    public synchronized static void setVarSet() {
        Temp.varSet=true;
    }

    public synchronized static boolean isVarSet() {
        return Temp.varSet;
    }
}

Test class

public class Test{
        public Test() {
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    Model model= new Model();
                    View view = new View();
                    Controller controller=new Controller(model, view);
                    Temp.setVarSet();
                  ...
                }
            });
        }
    }

What can be reason? I set method isVarSet() synchronized but it didn't help.
EDIT This code works too.

Test test = Test()        
while(!Temp.isVarSet()){
            Thread.sleep(100);
}
  • where are you calling `setVarSet()`? – Braj May 04 '14 at 14:48
  • Working as expected. Its not hanging the program. – Braj May 04 '14 at 14:53
  • @P82 - Are you sure the `run()` method is invoked? Have you put a breakpoint there and checked if it's reached in both cases? – Avi May 04 '14 at 14:55
  • @Avi Yes I am sure otherwise it wouldn't work with System.out.println("I am still here") too. –  May 04 '14 at 14:58
  • @P82 If you can create a test case we can run, we would be able to help. If it is a timing issue it would be too difficult to tell why. – John Vint May 04 '14 at 15:17
  • possible duplicate of [Loop doesn't see changed value without a print statement](http://stackoverflow.com/questions/25425130/loop-doesnt-see-changed-value-without-a-print-statement) – Boann Aug 23 '14 at 10:27

4 Answers4

5

You didn't publish what happens in Temp and isVarSet but most probably you change a variable. This variable must be marked volatile.

If your class looks like this:

public class Temp {
   private static boolean someFlag;

   public static boolean isVarSet() {
      return someFlag;
   }
}

And your loop is the same as the example, the compiler thinks that there's no need to read the flag over and over again because the flag is not changed inside the loop and it optimizes to not read the flag over and over.

Marking someFlag as volatile:

private static volatile boolean someFlag;

Will force the runtime to check the flag on each iteration and not just assume that the value hasn't changed. In this case, it will work.

From Oracle docs about atomic access:

Atomic actions cannot be interleaved, so they can be used without fear of thread interference. However, this does not eliminate all need to synchronize atomic actions, because memory consistency errors are still possible. Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable. This means that changes to a volatile variable are always visible to other threads. What's more, it also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change.

Avi
  • 21,182
  • 26
  • 82
  • 121
  • @Avi If the OP synchronized the reads and writes with `synchronized` volatile wouldn't make a difference. – John Vint May 04 '14 at 15:08
  • @JohnVint - OP posted the question without sharing the code of `Temp`. (S)he added it only following my answer. – Avi May 04 '14 at 15:09
2
  1. Even after you made variable as volatile .
  2. if you add SOP in while loop it is working

These two usecase gives me another thought. just try it.

Since your read and write methods are sync , in your while loop

while(!Temp.isVarSet()){
}

It is nothing doing other than calling the method, it may possible this sync method holds the lock on the Temp Object which does not allow other thread to modify the values (though sync setMethod) .

While add SOP inside the while , it is doing some work on IO and thus it is allowing some time slice to other thread get the lock of Temp and modify the same.

Could you please try remove Sync from read method , just for testing purpose and post your results.

public class Temp {

    private volatile static boolean varSet=false;

    public synchronized static void setVarSet() {
        Temp.varSet=true;
    }

    public  static boolean isVarSet() {
        return Temp.varSet;
    }
}
Mani
  • 3,274
  • 2
  • 17
  • 27
  • No, removing synchronized didn't help. The only that works is Thread.sleep(N) –  May 04 '14 at 15:17
1

This works perfect for me:

public class ThreadTest {

    public static void main(String[] args) throws Exception {

        Thread t1 = new TheThread();
        t1.start();

        // wait
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getId() + " will now setVarSet()");
        Temp.setVarSet();
        System.out.println(Thread.currentThread().getId() + " setVarSet() setted");

        t1.join();
        System.out.println(Thread.currentThread().getId() + " end programm");

    }

    private static class TheThread extends Thread {

        @Override
        public void run() {

            System.out.println(Thread.currentThread().getId() + " enter run");

            while (!Temp.isVarSet()) {
                System.out.println(Thread.currentThread().getId() + " running");
                try {
                    Thread.sleep((int) (Math.random() * 100));
                } catch (InterruptedException e) {
                    // ignore
                }
            }

            System.out.println(Thread.currentThread().getId() + " exit run");
        }
    }

    private static class Temp {

        private volatile static boolean varSet = false;

        public static void setVarSet() {
            Temp.varSet = true;
        }

        public static boolean isVarSet() {
            return Temp.varSet;
        }
    }

}

Can you please post a complete example?

salyh
  • 2,095
  • 1
  • 17
  • 31
1

Its working as expected without hanging the program.

private volatile static boolean varSet = false;

public synchronized static void setVarSet() {
    varSet = true;
}

public synchronized static boolean isVarSet() {
    return varSet;
}

public static void main(String[] args) throws InterruptedException {

    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            while (!TestDemo.isVarSet()) {
                // System.out.println("I am still here");
            }
            System.out.println("Variable set");

        }

    });
    t1.start();

    Thread.sleep(1000); // put delay to give the chance to execute above thread

    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            // Model model= new Model();
            // View view = new View();
            // Controller controller=new Controller(model, view);
            setVarSet();
        }
    });
}
Braj
  • 46,415
  • 5
  • 60
  • 76