Do while loops stop executing after a while? [duplicate] - java

This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 4 years ago.
So Im experimenting a bit with multithreading currently, since im still pretty new to Java. Now, I have multiple threads that all influence the same long variable. However, it seems that afer a while of not doing anything but checking the if statement the while loop just stops executing (as in, it loops infinitely). It does work if i just print something within the while-loop.
Does not work:
while(true){
if(longVariable < 2)
break;
}
Does somehow work:
while(true){
System.out.println("hi");
if(longVariable < 2)
break;
}
Why is this?

while(true){
if(longVariable < 2)
break;
}
In this code, there is no reason for the JVM to believe that longVariable will ever change. It can effectively rewrite it to:
long cached = longVariable;
while(true){
if(cached < 2)
break;
}
Which loops infinitely if longVariable is at least two when it executes, because nothing can change cached.
You have to give the compiler a hint that this rewrite isn't allowed. It works with the System.out.println on your JVM because it happens to be implemented with synchronization (which is common, but not required). This inserts memory barriers which means that the cached value of longVariable is invalidated, and has to be read again.
But it's not guaranteed to work. To make it work correctly, either declare the variable volatile:
volatile long longVariable
which prevents its value from being cached.
Or use something like an AtomicLong instead of a plain long variable.
Or, most onerously, use explicit synchronization (ensuring that all reads of and writes to the variable are synchronized on the same "something"):
long v;
synchronized (something) {
v = longVariable;
}
if (v < 2) ...

When you have a non volatile variable which is not updated by a thread, it is free to inline it.
In your first case, once the code has compiled by the JIT, it might no longer read the value and instead make the condition always true.
In the second case, you have a thread safe operation. println on System.out is a synchronized method. This adds a read and write barrier and prevents the JIT from optimising the read operation away.
If you try this, it should also work.
while(true){
synchronized("hi") { } // does nothing but add memory barriers.
if(longVariable < 2)
break;
}
It also slows down the code by more than 1000x so the method might not have been JITed by the time you try to stop the thread.
The simple solution is to make the variable volatile and it will be read in a thread safe manner every time.

Related

While-loop stops checking if-statement? [duplicate]

This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 5 years ago.
I have a short while loop like:
boolean a = false;
MyClass b = new MyClass();
b.b = false;
// b is used in other thread...
while(!a){
if(b.b){
throw new Exception("b is true");
}
}
In this case a will never became true, but after some runs the boolean variable b.b should became true. Strangely the while-loop was never left and my programm endet in an endless loop.
I woundered why and decided to add a System.out.print statement to the loop:
while(!a){
if(b.b){
throw new Exception("b is true");
}
System.out.println("there is something more to execute");
}
Remarkably my code works like it should be. The while loop runs over the if statement until b.b is true and the throwing of the exception leaves the loop.
Could it be that in the first case the program stops checking the if statement because the compiler thinks that it is not necessary to check again? If not, could anybody explain to me, why the first case does not work but the second one does?
You need to mark your variables (whichever have got access to multiple threads) as volatile if you are working in a multithreaded environment, otherwise, it is not guaranteed for the current thread to see the results written by another thread.
In other words, one thread writes (changes) the value of your variable a and the other thread is not guaranteed to see it (because threads might copy/cache the variables), which is causing your while loop not to break.
I suggest you look here and understand how volatile works in a multithreaded environment. Below text (emphasis mine) taken from the same link:
Changes to a volatile variable are always visible to other threads. 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.

System.out.println Line Affecting Execution of the Logic

I have run into an incredibly strange phenomenon. I am currently programming an instant messenger program in Java and I have a variable to represent whether a new user has connected (this is of in a separate class). Here is the code in question where the object ListenerThread extends Thread :
boolean listenerThreadConnected = ServerDriver.getListenerThread().connected;
System.out.println("Whatever in here");
if(listenerThreadConnected){
...
System.out.println("In the if statement");
...
}
So, this code works. When listenerThreadConnected = true the if statement executes and it outputs In the if statement and does all of the other stuff in the if statement. However, I changed no other code other than commenting out the System.out.println("Whatever in here") and the if statement didn't trigger and there was no sign of the In the if statement being outputted. My code looked like this:
boolean listenerThreadConnected = ServerDriver.getListenerThread().connected;
//System.out.println("Whatever in here");
if(listenerThreadConnected){
...
System.out.println("In the if statement");
...
}
I am quite perplexed. How could this System.out.println affect the actual logic? I know this question is very open-ended, but have you ever had a similar experience? For some context, this is all in a while loop and ListenerThread is a concurrently running Thread. I can't seem to replicate this result except in my current code.
[EDIT] Replacing the System.out.println with a Thread.sleep(1) also seems to work, so this leads me to think that it is a concurrency issue.
Not so extrange at all, you are for sure in a multi thread system and your app is getting an outdated boolean value, you need to ensure memory visibility when reading the variable listenerThreadConnected
How:?
Declare this boolean listenerThreadConnected as volatile and the error must be gone!
Note that System.out.println is often implemented as synchronized (even though this isn't documented), in order that you don't get the output of two threads interleaving.
Executing that statement has the effect of making updates to variables visible to the thread in which the synchronized method is executed (it is a "happens before" relationship).
By removing the System.out.println call, you remove this behaviour, so you may see outdated variables.
As #Xoce웃Пepeúpa says, make the variable volatile, or do something else to ensure memory visibility (e.g. changing it to an AtomicBoolean).

Value does not update in while loop unless printed out [duplicate]

This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
Ok, so I have a monitoring thread that checks a ArrayList size and does something after that size goes greater than a certain number. The problem I am having right now is the size value is never updated unless I have a print statement in my loop. Here is some code to show what exactly I have going.
while(working) {
// Get size function just returns the size of my list in my t class
int size = t.getSize();
if (size >= 10) {
//DO STUFF
}
}
This above code does not work. It never goes into the if statement. However, this works fine:
while(working) {
// Get size function just returns the size of my list in my t class
int size = t.getSize();
System.out.println(size);
if (size >= 10) {
//DO STUFF
}
}
EDIT: getSize() code:
public ArrayList<byte[]> myQueue = new ArrayList<byte[]>();
public int getSize() {
return myQueue.size();
}
NOTE: I have another thread running that is updating and adding to my list in my t class.
Any help? this is really annoying to have it spitting out numbers when I am trying to debug in the console.
If the only thing changing between your working and non working code is the println statement, then you almost certainly have a threading issue. The System.out.println() statement adds a small pause which may coincidentally cause it to behave, but is not solving the issue. You could do something like:
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
}
...in place of this and check for the same behaviour, if indeed it is the same then this pretty much confirms the threading issue. However, as pointed out below println() also does a few other things such as causing a memory barrier, so this isn't a foolproof test. Another, perhaps better check could be to temporarily swap out ArrayList for Vector, which is thread safe - though this is a legacy collection so not recommended for use in the final code.
If this is the case, it sounds like you're not synchronising on ArrayList calls properly - ArrayList is not a thread safe collection. Whenever you read or write to the list, do it inside a synchronized block like so, synchronizing on the list:
synchronized(list) {
list.whatever();
}
...which will ensure that only one thread can access the ArrayList at once, hopefully solving the threading issue.
ArrayList is not synchronized, or otherwise prepared for use in two threads at once. In JLS terms, there is no happens-before relationship between the addition of elements in one thread and a size() call in another thread.
The cleanest solution would be to use a synchronized List implementation. You can either use Vector, or create a synchronized wrapper around your ArrayList using Collections.synchronizedList().
Your reader is starving the writer so it never gets a chance to run, never adding anything to your list.
By adding a I/O call (system.out.print or Thread.sleep) you put the reader thread in a blocking state which allows other one to run.
Generally, loops which consumes 100% CPU like this is bad. At least add a short sleep/yield somewhere in the loop.
Without seeing any other code there are a number of things that can be going on here. If you give us a short reproduce able example that may help.
As far as 'a number of things' It is possible that the the compiler can re-order the write of size outside of the while loop for instance
int size = t.getSize();
while(working){
if(size >= 10){
}
}
But again that is just speculation at this point.

IF statement only executes if it's preceded with a 'sysout' of the value it is testing against [duplicate]

This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
I'm getting a very strange error. I have the following code:
while (true) {
System.out.println(model.getLightState());
if (model.getLightState() == 1) {
System.out.println("Entered..");
view.driveThroughJunction();
break;
}
}
Now, my program enters the if statement when the light state changes to '1' and executes the code that's fine. But this ONLY works if I have that print out statement after the while loop is entered. I find that weird. Will a 'sysout' line have any effect on the if statement? Apparently it does for the above case.
Any ideas to why this is ?
EDIT:
(in the model class)
public final byte getLightState() {
return lightChanger.getLightValue();
}
(in lightchanger class)
public byte getLightValue() {
return light.getState();
}
(in the light class)
public final byte getState() {
return this.state;
}
You have a synchronization problem, leading to a visibility problem. If no synchronization is used when reading and writing a variable shared by multiple threads, there is no guarantee that the value written by one thread is visible to other threads.
To fix that you need to do one of those things:
make the state field volatile
change the state field type to AtomicInteger
synchronize every access to the state field (using the synchronized keyword), using the same lock every time, of course.
Your sysout call makes the value visible because it internally calls some method that flushes the state of the registers to the main memory (by writing to a volatile field or calling a synchronized method, for example).
You should declare your model instance as volatile.
Volatile keyword in Java is used as an indicator to Java compiler and Thread that do not cache value of this variable and always read it from main memory. So if you want to share any variable in which read and write operation is atomic by implementation you should declare them as volatile variable.
Read more: http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html#ixzz2DFw4l8AW
From your comments it is apparent that more than one thread is accessing the same instance of model and performing read/write in the same instance of model. Without volatile threads do cache the value of model instance and hence end up in dirty reads. With System.out.println happening your read/write operation is delayed by a bit (due to output writing) hence thread is able to refresh the cached value from main memory.

Infinite loop problem with while loop and threading [duplicate]

This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 8 years ago.
Using a basic example to illustrate my problem I have 2 near-identical bits of code.
This code causes the while loop to run infinitely.
private boolean loadAsset() {
new Thread(new Runnable() {
#Override
public void run() {
// Do something
loaded = true;
}
}).start();
while (!loaded) {
// System.out.println("Not Loaded");
}
System.out.println("Loaded");
return false;
}
This code however (i.e. doing something in the while loop) causes the loaded variable to be successfully evaluated and allows the while loop to break and method to finish.
private boolean loadAsset() {
new Thread(new Runnable() {
#Override
public void run() {
// Do something
loaded = true;
}
}).start();
while (!loaded) {
System.out.println("Not Loaded");
}
System.out.println("Loaded");
return false;
}
Can anyone explain to me why this is?
The first loop only "appears" to run infinitely. You're actually running an "active wait", burning 100% of your CPU, such that your OS or JVM can't make a context switch and let the other thread run.
With the System.out.println() on the other hand, there is I/O involved, resulting in a somewhat "inactive wait". The OS or JVM can switch contexts and the other thread starts.
If you'd run your first program for 10 hours, I'm sure the loop would break eventually
Check that 'loaded' is definitely declared as volatile.
Explanation: if a variable is read and/or written by multiple threads, then you need to take appropriate thread-safety measures. One such thread-safety measure is volatile, which is suitable for primitive values (or object references) which are read or written as 'simple' actions with the value written on a given occasion not depending on the previously read value. For more information, I have an article about volatile on my web site (along with other information about thread-safety generally) that may be of help.
If loaded is not volatile, the JIT is free to optimise it by placing it in a register and not loading it from memory every time. In the second case, the loop is too complex for the JIT to assume it doesn't need to load loaded each time.
Note: its is the JIT not the javac compiler which optimises the code.
Read up on Memory Consistency Errors. Basically, different threads have inconsistent views of what should be the same data. In order to resolve this, read up on Synchronization. Or simply declare loaded as volatile, since its value is only being written by a single thread.
I believe you are experiencing a Busy Wait with the empty loop, which will never sleep. Thus, your Thread to set loaded to true never runs.

Categories

Resources