In the following scenario, the boolean 'done' gets set to true which should end the program. Instead the program just keeps going on even though the while(!done) is no longer a valid scenario thus it should have halted. Now if I were to add in a Thread sleep even with zero sleep time, the program terminates as expected. Why is that?
public class Sample {
private static boolean done;
public static void main(String[] args) throws InterruptedException {
done = false;
new Thread(() -> {
System.out.println("Running...");
int count = 0;
while (!done) {
count++;
try {
Thread.sleep(0); // program only ends if I add this line.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(2000);
done = true; // this is set to true after 2 seconds so program should end.
System.out.println("Done!"); // this gets printed after 2 seconds
}
}
EDIT: I am looking to understand why the above needs Thread.sleep(0) to terminate. I do not want to use volatile keyword unless it is an absolute must and I do understand that would work by exposing my value to all threads which is not my intention to expose.
Each thread have a different cached version of done created for performance, your counter thread is too busy making the calculations for count that it doesnt give a chance to reload done.
volatile ensures that any read/write is done on the main memory, always update the cpu cache copy.
Thread.sleep always pause the current thread, so even if 0 your counter thread is interrupted by some time <1ms, that is enough time for the thread to be adviced of done variable change.
I am no Java expert man, I don't even program in java, but let me try.
A thread on stackoverflow explains the Java Memory model: Are static variables shared between threads?
Important part: https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility
Chapter 17 of the Java Language Specification defines the
happens-before relation on memory operations such as reads and writes
of shared variables. The results of a write by one thread are
guaranteed to be visible to a read by another thread only if the write
operation happens-before the read operation. The synchronized and
volatile constructs, as well as the Thread.start() and Thread.join()
methods, can form happens-before relationships.
If you go through the thread, it mentions the "Happens before" logic when executing threads that share a variable. So my guess is when you call Thread.sleep(0), the main thread is able to set the done variable properly making sure that it "Happens first". Though, in a multi-threaded environment even that is not guaranteed. But since the code-piece is so small it makes it work in this case.
To sum it up, I just ran your program with a minor change to the variable "done" and the program worked as expected:
private static volatile boolean done;
Thank you. Maybe someone else can give you a better explanation :P
Related
Can someone please explain to me what I am missing: when I call Thread.sleep(1000) I suppose both threads should be executed in 1s so after that why should I make doSlice false to stop threads in 1s
why Thread.sleep() just doesn't stop them in 1s. I mean after 1s run method even shouldn't be called to check while condition:
public class ExecutionScheduling extends Thread{
public int slice_count=0;
public boolean doSlice=true;
public String name;
public ExecutionScheduling(String name){
this.name=name;
}
public void run() {
while (doSlice) {
slice_count++;
System.out.println(name);
}
}
public static void main(String[] args) throws InterruptedException {
ExecutionScheduling executionScheduling=new ExecutionScheduling("ex");
ExecutionScheduling executionScheduling1=new ExecutionScheduling("ex1");
executionScheduling.start();
executionScheduling1.start();
Thread.sleep(1000);
executionScheduling.doSlice=false;
executionScheduling1.doSlice=false;
System.out.println("ex: "+executionScheduling.slice_count);
System.out.println("ex1: "+executionScheduling1.slice_count);
}
}
Can someone please explain to me what I am missing
What you are missing is memory synchronization between the threads. When you start your 2 background threads, they have their own local memory (on their own CPUs) and you need to specifically update any shared data between them.
What is complicating the code is that System.out.println(...) is a synchronized method so it is giving you some memory synchronization "for free" but you shouldn't depend on it (see below). This means that if you removed that debug code, your program is going to be behave differently. Be careful of any usage of System.out.print* in threaded code.
Thread.sleep(1000);
When you run this sleep command, it will cause the main thread to go to sleep but the 2 background threads continue to run. They are each updating their own copy of slice_count but there is no guarantee that the main thread will see these updates.
// need to add the volatile keyword here
private volatile int slice_count;
By adding the volatile Java keyword to slice_count, this marks the field as being accessed by multiple threads. When the main thread the accesses slice_count, it will read the most updated value of it. You might also want to look into AtomicInteger which wraps a volatile int but allows multiple threads to do stuff like incrementAndGet().
Another place where you have memory sync issues is:
executionScheduling.doSlice = false;
executionScheduling1.doSlice = false;
So the doSlice field also needs to be volatile:
// need to add the volatile keyword here
public volatile boolean doSlice = true;
And lastly, in no order:
Your fields should be private if at all possible.
It should be executionScheduling1 and executionScheduling2.
It is a better pattern to define a Runnable instead of a Thread. See: https://stackoverflow.com/a/541527/179850
You might consider doing a join() to wait or each of the threads to finish their work before you print out their results.
// set the doSlices to false
executionScheduling.join()
executionScheduling1.join()
// printf results
If you add the join() calls then this will handle the memory synchronization for you in terms of slice_count so those no longer need to be volatile as long as you access them after the join() calls finish. Yes this is confusing. Thread coding is non-trivial. You will still need the doSlice fields to be volatile because they are accessed before join() finishes.
In JSR-133 section 3.1, which discusses the visibility of actions between threads - it is mentioned that the code example below, which does not utilise the volatile keyword for the boolean field, can become an infinite loop if two threads are running it. Here is the code from the JSR:
class LoopMayNeverEnd {
boolean done = false;
void work() {
while (!done) {
// do work
}
}
void stopWork() {
done = true;
}
}
Here is a quote of the important bit in that section that I'm interested in:
... Now imagine that two threads are created, and that one
thread calls work(), and at some point, the other thread calls stopWork(). Because there is
no happens-before relationship between the two threads, the thread in the loop may never
see the update to done performed by the other thread ...
And here is my own Java code I wrote just so I can see it loop:
public class VolatileTest {
private boolean done = false;
public static void main(String[] args) {
VolatileTest volatileTest = new VolatileTest();
volatileTest.runTest();
}
private void runTest() {
Thread t1 = new Thread(() -> work());
Thread t2 = new Thread(() -> stopWork());
t1.start();
t2.start();
}
private void stopWork() {
done = true;
System.out.println("stopped work");
}
private void work() {
while(!done){
System.out.println("started work");
}
}
}
Although the results from consecutive executions are different - as expected - I don't see it ever going into an infinite loop. I'm trying to understand how I can simulate the infinite loop that the documentation suggests, what am I missing? How does declaring the boolean volatile, remove the infinite loop?
The actual behavior is OS and JVM specific. For example, by default, Java runs in client mode on 32-bit Windows and in server mode on the Mac. In client mode the work method will terminate, but will not terminate in server mode.
This happens because of the Java server JIT compiler optimization. The JIT compiler may optimize the while loop, because it does not see the variable done changing within the context of the thread. Another reason of the infinite loop might be because one thread may end up reading the value of the flag from its registers or cache instead of going to memory. As a result, it may never see the change made by the another thread to this flag.
Essentially by adding volatile you make the thread owning done flag to not cache this flag. Thus, the boolean value is stored in common memory and therefore guarantees visibility. Also, by using volatile you disabling JIT optimization that can inline the flag value.
Basically if you want to reproduce infinite loop - just run your program in server mode:
java -server VolatileTest
The default, non-volatile, implicit declaration of all Java values allows the Jit compiler to "hoist" references to non-volatile values, out of loops so that they are only read 'once'. This is allowed after a tracing of execution paths can safely arrive at the fact that the methods called inside of such a loop, don't ever cause entry back into the classes methods where it might mutate the value of these non-volatile values.
The System.out.println() invocation goes to native code which keeps the JIT from resolving that 'done' is never modified. Thus the hoist does not happen when the System.out.println() is there and as you found out, the infinite loop is only happening with it removed where the JIT can resolve that there is no write to 'done'.
The ultimate problem is that this reference hoisting is conditional on "reachability" of a mutation of the value. Thus, you may have moments where there is no reach to a mutation of the value, during development, and thus the hoist happens and suddenly you can't exit the loop. A later change to the loop might use some function that makes it impossible to discern that the value cannot be written by the logic in the loop, and the hoist disappears and the loop works again.
This hoist is a big problem for many people who don't see it coming. There is a pretty large group of belief now that safe Java has class level variables either declared as volatile or final. If you really need a variable to be "optimizable", then don't use a class level variable and instead make it a parameter, or copy it into a local variable for the optimizer to go after. Doing this with read only access helps manage "dynamic" changes in a value that disrupt predictable execution paths too.
There is has been recurring discussion on the java concurrency mailing list about this issue. They don't seem to believe that this is a problem for Java developers and that this "optimization" of reference is far more valuable to performance than problematic to development.
Here is an example of the usage of volatile keyword.
public class Test3{
public static volatile boolean stop = false;// if volatile is not set, the loop will not stop
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(){
public void run() {
int i=0;
while(!stop){
i++;
// add this line
// System.out.println(i);
// or this block
// try {
// Thread.sleep(1);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
}
};
thread.start();
Thread.sleep(2000);
stop = true;
}
}
It's easy to understand that if volatile is set, JVM should load the updated value from memory while checking its value, then the while loop can stop as expected. But question is, should not the static variable change at the same time? There may be some delay but eventually, this change should be detected. no? I've tested that if we add some print code or sleep code, this change can be detected? Can someone teach me why it likes that? Maybe it's about the JMM.
Time, in the sense of wall-clock time, has no meaning for the memory visibility. What matters is the synchronization order between synchronization actions. Reading and writing a non-volatile field is not a synchronization action, so in the absence of any other synchronization action, there is no ordering between them.
So even if the main thread completed a year ago, so the write must have been done from the main thread’s perspective, the subthread may continue to run, running forever; the write has not happened from its perspective. It also doesn’t know that the main thread has terminated. Note that performing an action capable of detecting that the other thread has terminated, is a synchronization action that may establish an order.
But since the actual program behavior also depends on the JIT compiler and optimizer, some code changes may have an impact, even if it is not guaranteed.
E.g. inserting sleep does not imply any memory visibility:
JLS §17.3. Sleep and Yield:
It is important to note that neither Thread.sleep nor Thread.yield have any synchronization semantics. In particular, the compiler does not have to flush writes cached in registers out to shared memory before a call to Thread.sleep or Thread.yield, nor does the compiler have to reload values cached in registers after a call to Thread.sleep or Thread.yield.
But it may stop the optimizer from considering the loop to be a hotspot that needs optimizations.
When you insert a System.out.println statement, the internal synchronization of the PrintStream may have an impact on the overall memory visibility, though this effect also isn’t guaranteed, as the main thread does not synchronize on that PrintStream.
By the way there isn’t even a guaranty that preemptive thread switching ever happens between threads of the same priority. Hence, it would be a valid execution, if a JVM tries to complete your subthread after start() has been called, before giving the CPU back to the main thread.
In that execution scenario, with no sleep in the loop, the subthread would never give up the CPU, so stop would never be set to true, even if declared volatile. That would be another reason to avoid polling loops, though there might be no real life execution environment without preemptive thread switching anymore. Most of today’s execution environments even have multiple CPUs so not giving up a CPU won’t prevent other threads from executing.
Still, to be formally correct, you should enforce an ordering between a write to the stop variable and the reading of the variable, like declaring the variable volatile and insert an action that may cause the thread to release the CPU eventually, when quit is still false.
It's easy to understand that if volatile is set, JVM should load the
updated value from memory while checking its value, then the while
loop can stop as expected.
volatile is some kind of rule or mechanism, not about concrete implemention above. It is used to build happends-before relationship between threads:
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.
Without volatile or other synchronization, the update to static variable could be seen to other threads with some delay, and could not be seen forever because memory barriar. It is uncertain. Even you add some print code or sleep code, and find it works, it does not mean it can still work in other enviroment or other moment.
However, if you add the print code in both the while loop and the main thread:
while(!stop){
i++;
System.out.println(i);
}
and
stop = true;
System.out.println("some");
JMM can gurantee that the stop = true will be detected in the loop(at least on oracle jdk 8u161), this is because System.out.println is synchronized, which also can build a happens-before relationship between involved threads, see the source code:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
While trying to unit test a threaded class, I decided to use active waiting to control the behavior of the tested class. Using empty while statements for this failed to do what I intended. So my question is:
Why does the first code not complete, but the second does?
There is a similar question, but it doesn't have a real answer nor an MCVE and is far more specific.
Doesn't complete:
public class ThreadWhileTesting {
private static boolean wait = true;
private static final Runnable runnable = () -> {
try {Thread.sleep(50);} catch (InterruptedException ignored) {}
wait = false;
};
public static void main(String[] args) {
wait = true;
new Thread(runnable).start();
while (wait); // THIS LINE IS IMPORTANT
}
}
Does complete:
public class ThreadWhileTesting {
private static boolean wait = true;
private static final Runnable runnable = () -> {
try {Thread.sleep(50);} catch (InterruptedException ignored) {}
wait = false;
};
public static void main(String[] args) {
wait = true;
new Thread(runnable).start();
while (wait) {
System.out.println(wait); // THIS LINE IS IMPORTANT
}
}
}
I suspect that the empty while gets optimized by the Java compiler, but I am not sure. If this behavior is intended, how can I achieve what I want? (Yes, active waiting is intented since I cannot use locks for this test.)
wait isn't volatile and the loop body is empty, so the thread has no reason to believe it will change. It is JIT'd to
if (wait) while (true);
which never completes if wait is initially true.
The simple solution is just to make wait volatile, which prevents JIT making this optimization.
As to why the second version works: System.out.println is internally synchronized; as described in the JSR133 FAQ:
Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory.
so the wait variable will be re-read from main memory next time around the loop.
However, you don't actually guarantee that the write of the wait variable in the other thread is committed to main memory; so, as #assylias notes above, it might not work in all conditions. (Making the variable volatile fixes this also).
The short answer is that both of those examples are incorrect, but the second works because of an implementation artifact of the System.out stream.
A deeper explanation is that according to the JLS Memory Model, those two examples have a number of legal execution traces which give unexpected (to you) behavior. The JLS explains it like this (JLS 17.4):
A memory model describes, given a program and an execution trace of that program, whether the execution trace is a legal execution of the program. The Java programming language memory model works by examining each read in an execution trace and checking that the write observed by that read is valid according to certain rules.
The memory model describes possible behaviors of a program. An implementation is free to produce any code it likes, as long as all resulting executions of a program produce a result that can be predicted by the memory model.
This provides a great deal of freedom for the implementor to perform a myriad of code transformations, including the reordering of actions and removal of unnecessary synchronization.
In your first example, you have one thread updating a variable and a second thread updating it with no form of synchronization between the tro threads. To cut a (very) long story short, this means that the JLS does not guarantee that the memory update made by the writing thread will every be visible to the reading thread. Indeed, the JLS text I quoted above means that the compiler is entitled to assume that the variable is never changed. If you perform an analysis using the rules set out in JLS 17.4, an execution trace where the reading thread never sees the change is legal.
In the second example, the println() call is (probably) causing some serendipitous flushing of memory caches. The result is that you are getting a different (but equally legal) execution trace, and the code "works".
The simple fix to make your examples both work is to declare the wait flag as volatile. This means that there is a happens-before relationship between a write of the variable in one thread and a subsequent read in another thread. That in turn means that in all legal execution traces, the result of the write will be visible to to the readin thread.
This is a drastically simplified version of what the JLS actually says. If you really want to understand the technical details, they are all in the spec. But be prepared for some hard work understanding the details.
I was trying examples from JCIP and Below program should not work but even if I execute it say 20 times it always work which means ready and number are becoming visible even if it should in this case
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread implements Runnable {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
//Number of Processor is 4 so 4+1 threads
new Thread(new ReaderThread()).start();
new Thread(new ReaderThread()).start();
new Thread(new ReaderThread()).start();
new Thread(new ReaderThread()).start();
new Thread(new ReaderThread()).start();
number = 42;
ready = true;
}
}
On my machine it always prints
4 -- Number of Processors
42
42
42
42
42
According to Listing 3.1 of JCIP It should sometimes print 0 or should never terminate it also suggest that there is no gaurantee that ready and number written by main thread will be visible to reader thread
Update
I added 1000ms sleep in main thread after strating all threads still same output.I know program is broken And I expect it behave that way
This program is broken since ready and number should be declared as volatile.
Due to the fact that ready and number are primitive variables, operations on them are atomic but it is not guaranteed that they will be visible by other threads.
It seems that the scheduler runs the threads after main and that is why they see the number and ready being initialized. But that is just one scheduling.
If you add e.g. a sleep in main so as to affect the scheduler you will see different results.
So the book is correct, there is no guarantee whether the Runnables running in separate threads will ever see the variable's being updated since the variables are not declared as volatile.
Update:
The problem here is that the due to the lack of volatile the compiler is free to read the field ready just once, and reuse the cached value in each execution of the loop.
The program is inherently flawed. And with threading issues the problem usually appears when you deploy your application to the field....
From JSL:
For example, in the following (broken) code fragment, assume that
this.done is a non-volatile boolean field:
while (!this.done)
Thread.sleep(1000);
The compiler is free to read the field this.done just once, and reuse
the cached value in each execution of the loop. This would mean that
the loop would never terminate, even if an other thread changed the
value of this.done.
What is important to keep in mind is that a broken concurrent program might always work with the right combination of JVM's options, machine architecture etc. That does not make it a good program, as it will probably fail in a different context: the fact that no concurrency issue shows up does not mean there aren't any.
In other words, you can't prove that a concurrent program is correct with testing.
Back to your specific example, I see the same behaviour as what you describe. But, if I remove the Thread.yield() instruction in the while loop, 3 out of 8 threads stop and print 42, but the rest don't and the program never ends.