Java: if statement in an infinite while loop

I am new to Java, and the following may be obvious, but it puzzles me. Consider the following code:

while(1>0){ if(x!=0){ //do something } } 

The variable x changes in another thread. However, the code in the if statement is never executed, even if x is not zero. If I changed the code to the next

 while(1>0){ System.out.println("here"); if(x!=0){ //do something } } 

the code in the if statement now executes when x is no longer zero. I suspect this is due to the rules of the Java compiler, but it is very confusing to me. Any help clarifying this would be greatly appreciated.

+4
source share
5 answers

If x changes in another thread, you probably see a side effect of the fact that you did not synchronize access to this variable.

The Java memory and streaming model is quite complex, so I recommend that you get a copy of Java Concurrency in practice from Brain Goetz and read.

The short answer is to make sure that access to x enclosed in a synchronized block:

 while (1 > 0) { int temp; synchronized (this) { temp = x; } if (temp != 0) { // Do something } } 

And similarly in code that modifies x .

Note that this example stores x in a temporary variable because you want the synchronized blocks to be as small as possible - they use mutual exclusion locks, so you don't want to do too much there.

Alternatively, you can simply declare x volatile , which is likely to be sufficient for your use case. I suggest you upgrade to the synchronized version because you will eventually need to know how to use synchronized correctly so that you can now learn it.

+7
source

If you use multi-threaded code, check that the variable x is unstable.

+2
source

What is the reason why nothing happens without System.out.println("here"); is well explained by Cameron Skinner's answer.

So why does the block inside if(x!=0) work when println used? println executes a synchronized block (see PrintStream.write(String s) ). This causes the current thread to retrieve the System.out state from main memory and update the thread's cache before allowing the thread to execute any further line of code. An amazing side effect is that also the states of other variables , such as your x , are also updated in this way, although the lock x not involved in synchronization. It was called feedback .

If I use free text to describe the formalities described in the Java Memory Model Specification : it says that the operations performed before the release of lock operations occur before those performed after the next receipt of this lock.

I will demonstrate this with an example. Assume that Thread 1 is running, and only when it ends does Thread 2 start. Also suppose that x , y and z are variables shared by both threads. Note that we can only determine the value of z inside the synchronized y block.

 Thread 1: x = 0; synchronized(y) { } Thread 2: x = 1 z = x; // here there no guarantee as to z value, could be 0 or 1 synchronized(y) { z = x; // here z has to be 0! } 

It is, of course, a very bad practice to rely on synchronization ...

+1
source

This is probably a compiler optimization. It recognizes that as part of the while loop, the variable never changes and caches the value, rather than reading it from memory every time. To avoid this behavior, simply declare the variable as mutable:

 private volatile int x; 
0
source

Check also what you are doing inside the if. These are only operations with memory, it is a hell of a lot faster than writing to the console, so before changing the state you perform much more operations in the latter case.

0
source

Source: https://habr.com/ru/post/1387331/


All Articles