Lets save I have this code which exhibits stale cache reads by a thread, which prevent it from exiting its while loop.
class MyRunnable implements Runnable {
boolean keepGoing = true; // volatile fixes visibility
#Override public void run() {
while ( keepGoing ) {
// synchronized (this) { } // fixes visibility
// Thread.yield(); // fixes visibility
System.out.println(); // fixes visibility
}
}
}
class Example {
public static void main(String[] args) throws InterruptedException{
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
Thread.sleep(100);
myRunnable.keepGoing = false;
}
}
I believe the Java Memory Model guarantees that all writes to a volatile variable synchronize with all subsequent reads from any thread, so that solves the problem.
If my understanding is correct the code generated by a synchronized block also flushes out all pending reads and writes, which serves as a kind of "memory barrier" and fixes the issue.
From practice I've seen that inserting yield and println also makes the variable change visible to the thread and it exits correctly. My question is:
Is yield/println/io serving as a memory barrier guaranteed in some way by the JMM or is it a lucky side effect that cannot be guaranteed to work?
Edit: At least some of the assumptions I made in the phrasing of this question were wrong, for example the one concerning synchronized blocks. I encourage readers of the question to read the corrections in the answers posted below.
No. It is not guaranteed, by either the JLS or the javadocs for the classes or methods you are using there.
In current implementations, there are in practice memory barriers in yield() and println. (If you were to dig deeply into the implementation code, you should be able to figure out how they come about and what purpose they serve.)
However, there is no guarantee that these memory barriers will exist for all implementations of Java1 on all platforms. The specs do not specify that the happens before relations exist2, and therefore they do not require3 memory barriers to be inserted.
Hypothetically:
Suppose that Thread.yield() was implemented as a no-op. (In the same way that System.gc() can be a no-op.)
Suppose that the output stream stack was optimized in a way that it synchronization was no longer needed under the hood. For example, suppose that the JVM could deduce that an particular output stream was thread-confined, and there was no need for a memory barrier when writing to its buffer.
Now I don't personally think that those changes are likely to happen. (And they may not even be feasible.) But if they did happen, quite a few "broken" applications that currently depended on those serendipitous memory barriers would most likely stop working.
The point is: if you want guarantees, rely on what the specs say. The specs are the only real guarantee ... if your code needs to be portable.
1 - In particular, future ones.
2 - Indeed as Holger's answer explains, the javadocs for Thread clearly state that you cannot assume or rely on any synchronizing behavior happening for a yield(). That clearly means that there is no happens before between the yield() and any action on any other thread.
3 - The memory barriers are in fact an implementation detail. They are used by a typical compiler to implement the JMM's visibility guarantees. It is the guarantees that are the key, not the strategy used to implement them. Thus, any discussion of memory barriers, caches, registers, and so on is beside the point when you are trying to work out if multi-threaded code is correct.
Lets save I have this code which exhibits stale cache reads by a thread, which prevent it from exiting its while loop.
If you are referring to CPU caches, then this is a bad mental model (apart from not a suitable mental model for the JMM). Caches on modern CPUs are always coherent.
I believe the Java Memory Model guarantees that all writes to a volatile variable synchronize with all subsequent reads from any thread, so that solves the problem.
That is correct. There is a happens before edge between a write of a volatile variable and all the subsequent reads of the same volatile variable.
Blockquote If my understanding is correct the code generated by a synchronized block also flushes out all pending reads and writes, which serves as a kind of "memory barrier" and fixes the issue.
It is dangerous to reason in terms of memory barriers in combination with the JMM.
https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#myth-barriers-are-sane
There is a happens before edge between the release of a monitor and any subsequent acquire of that same monitor. So if you would access the keepGoing variable while it is protected by a lock, there is no data race.
Is yield/println/io serving as a memory barrier guarenteed in some way by the JMM or is it a lucky side effect that cannot be guaranteed to work?
Check the JLS and you will see there is no happens before edge between 2 yields. Perhaps there is a CPU memory barrier involved, but the problems could happen before the code hits the CPU. E.g. the JIT might optimize the code to:
if(!keepGoing){
return;
}
while(true){
Thread.yield();
println();
}
So in this case the code is already 'broken' before it is executed on the CPU since the code will never see the updated version of the 'keepGoing' variable.
I'm not sure if the Thread.yield() has any compiler barriers, if there is a compiler barrier than the JIT can't optimize out the load or store. But none of this is part of the specification.
Nothing in the specification guarantees flushing of any kind. This simply is the wrong mental model, assuming that there has to be something like a main memory that maintains a global state. But an execution environment could have local memory at each CPU without a main memory at all. So CPU 1 sending updated data to CPU 2 would not imply that CPU 3 knows about it.
In practice, systems have a main memory, but caches may get synchronized without the need to transfer the data to the main memory.
Further, discussing memory transfers end up in a tunnel vision. Java’s memory model also dictates, which optimizations a JVM may perform and which not. E.g.
nonVolatileVar = null;
Thread.sleep(100_000);
if(nonVolatileVar == null) {
// do something
}
Here, the compiler is entitled to remove the condition, and perform the block unconditionally, as the preceding statement (ignoring the sleep) has written null and other thread’s activities are irrelevant for non-volatile variables, regardless of how much time has elapsed.
So when this optimization has been performed, it doesn’t matter how many threads write a new value to this variable and “flush to memory”. This code won’t notice.
So let’s consult the specification
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.
I think, the answer to your question couldn’t be more explicit.
For completeness
I believe the Java Memory Model guarantees that all writes to a volatile variable synchronize with all subsequent reads from any thread, so that solves the problem.
All writes made prior to writing to a volatile variable will become visible to threads subsequently reading the same variable. So in your case, declaring keepGoing as volatile will fix the issue, as both threads consistently use it.
If my understanding is correct the code generated by a synchronized block also flushes out all pending reads and writes, which serves as a kind of "memory barrier" and fixes the issue.
A thread leaving a synchronized block establishes a happens-before relationship to a thread entering a synchronized block using the same object. If using a synchronized block in one thread appears to solve the issue despite you’re not using a synchronized block in the other, you’re relying on side effects of a particular implementation which is not guaranteed to continue to work.
Related
I'm going through Goetze's Java Concurrency in practice and am stuck on the section on memory visibility of shared variables when not using the synchronized keyword.
The code is as follows
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while(!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args){
new ReaderThread().start();
number=42;
ready=true;
}
}
The author says that this class could loop forever because the value of ready might never become visibile to the reader thread.
I don't understand this statement.
The way I see it is that first the main thread starts and sets the number and ready to true. But the other thread has its own stack and its own value of number and ready which is not synced with the main memory and these two threads have only their own copies of the variables.
Now the readerthread will supposedly keep in the loop forever. I want to know why the Thread.yield variable will not yield to the main thread and then the main thread should flush to the main memory and then the readerthread should pick up this new value and terminate the loop and print the correct value because that too should have been synched.
So I guess some questions I have are.
How often does the value in the cpu's cache get flushed/synced with main memory?
Can the value be not synced with the main memory is that also a possibility?
Why would this happen?
Does this memory visibility happen also when there is only once cpu core and one cpu cache or does it happen always?
I am having some trouble understanding the memory visibility problem though I understand race conditions and deadlocks. Is this something architecture specific?
How often does the value in the cpu's cache get flushed/synced with main memory?
Undefined. Cache flushing happens when the visibility guarantees specified in the JLS say that it needs to happen.
Can the value be not synced with the main memory is that also a possibility?
Yes.
Why would this happen?
Generally speaking, caches get flushed for a reason. The happens-before relationships indicate the places where a cache flush may be necessary.
Does this memory visibility happen also when there is only once cpu core and one cpu cache or does it happen always?
If there is only one core, then cache flushing is not an issue1.
I am having some trouble understanding the memory visibility problem though I understand race conditions and deadlocks. Is this something architecture specific?
Yes and no. The memory visibility may manifest differently depending on the hardware architecture among other things, but the way to write your code to give well-defined behavior is architecture independent.
If you really need a deep understanding of the memory visibility problem, you need to understand the Memory Model. It is described in laymans terms in Goetz et al Chapter 16, and specified in the JLS.
I want to know why the Thread.yield() call will not yield to the main thread and then the main thread should flush to the main memory
The Thread.yield() may yield to another runnable thread. However, by the time that yield() is called, it is quite likely that the main thread is no longer runnable. (Or it may still be running.)
The yield() does not create a happens-before between any statements in the main and child threads. Absent that happens-before relation, the runtime is not obliged to ensure that the result of the assignment by the main thread is visible to the child thread.
While Thread.yield() might perform a cache flush2, it would be a flush of the child thread's caches, not the parent thread's caches.
Hence, the child thread's loop may continue indefinitely.
1 - Actually, that may be an over-simplification. For example, in a system with one core and multiple hyperthreads with their own caches, cache flushing would be needed.
2 - For example, if the yield() does result in a context switch, then the context switch typically includes a cache flush as part of the thread state saving performed by the OS. However, yield() won't necessary result in a context switch. And besides, this aspect is not specified by the JLS.
Field visibility means that threads observer field values from the cache memory and can have different state from other cache in another core of the CPU. JVM does not guarantee field visibilty for different threads accessing shared resource and programmer needs to use sycchronized to prevent reading incorrect state or use volatile to guarantee the changes are flushed to other cache.
I was asked by interviewer is there any danger not to use volatile if we know for sure that threads will never interfere.
eg. we have:
int i = 10;
// Thread 1
i++;
// await some time and switch to Thread 2
getI();
I don't use any synchronization.
Do we have any danger to receive outdated value of i by second thread?
Without volatile or synchronized or read/write barrier, there is no guarantee that another thread will ever see a change you made, no matter how long your wait. In particular boolean fields can be inlined into the code and no read actually performed. In theory, int values could be inlined if the JVM detects the field is not changed by the thread (I don't believe it actually does though)
we know for sure that threads will never interfere.
This is not something you can know, unless the reading thread is not running when you perform the update. When thread starts it will see any changes which occurred before it started.
You might receive outdated values, yes.
The reason in short is:
Every thread in Java has its own little 'cache'. For performance reasons, threads keep a copy of the 'master' data in their own memory. So you basically have a main memory and a threadlocal one. The volatile keyword forces the thread to access the main memory and not its local one.
Refer to this for more information: http://www.ibm.com/developerworks/library/j-5things15/
If an interviewer asked me that question, I would answer in terms of the Java Language Specification. There is no "cache" or "main memory" in the JLS. The JLS talks about fields (a.k.a., instance variables and class variables) and it makes very specific guarantees about when an update to a field that happens in thread A will become visible in thread B. Implementation details like "cache" and "memory barriers" and can vary from one platform to another, but a program that is correct with respect to the JLS should (in theory) be correct on any Java platform.
I read this in an upvoted comment on StackOverflow:
But if you want to be safe, you can add simple synchronized(this) {}
at the end of you #PostConstruct [method]
[note that variables were NOT volatile]
I was thinking that happens-before is forced only if both write and read is executed in synchronized block or at least read is volatile.
Is the quoted sentence correct? Does an empty synchronized(this) {} block flush all variables changed in current method to "general visible" memory?
Please consider some scenerios
what if second thread never calls lock on this? (suppose that second thread reads in other methods). Remember that question is about: flush changes to other threads, not give other threads a way (synchronized) to poll changes made by original thread. Also no-synchronization in other methods is very likely in Spring #PostConstruct context - as original comment says.
is memory visibility of changes forced only in second and subsequent calls by another thread? (remember that this synchronized block is a last call in our method) - this would mark this way of synchronization as very bad practice (stale values in first call)
Much of what's written about this on SO, including many of the answers/comments in this thread, are, sadly, wrong.
The key rule in the Java Memory Model that applies here is: an unlock operation on a given monitor happens-before a subsequent lock operation on that same monitor. If only one thread ever acquires the lock, it has no meaning. If the VM can prove that the lock object is thread-confined, it can elide any fences it might otherwise emit.
The quote you highlight assumes that releasing a lock acts as a full fence. And sometimes that might be true, but you can't count on it. So your skeptical questions are well-founded.
See Java Concurrency in Practice, Ch 16 for more on the Java Memory Model.
All writes that occur prior to a monitor exit are visible to all threads after a monitor enter.
A synchronized(this){} can be turned into bytecode like
monitorenter
monitorexit
So if you have a bunch of writes prior to the synchronized(this){} they would have occurred before the monitorexit.
This brings us to the next point of my first sentence.
visible to all threads after a monitor enter
So now, in order for a thread to ensure the writes ocurred it must execute the same synchronization ie synchornized(this){}. This will issue at the very least a monitorenter and establish your happens before ordering.
So to answer your question
Does an empty synchronized(this) {} block flush all variables changed
in current method to "general visible" memory?
Yes, as long as you maintain the same synchronization when you want to read those non-volatile variables.
To address your other questions
what if second thread never calls lock on this? (suppose that second
thread reads in other methods). Remember that question is about: flush
changes to other threads, not give other threads a way (synchronized)
to poll changes made by original thread. Also no-synchronization in
other methods is very likely in Spring #PostConstruct context
Well in this case using synchronized(this) without any other context is relatively useless. There is no happens-before relationship and it's in theory just as useful as not including it.
is memory visibility of changes forced only in second and subsequent
calls by another thread? (remember that this synchronized block is a
last call in our method) - this would mark this way of synchronization
as very bad practice (stale values in first call)
Memory visibility is forced by the first thread calling synchronized(this), in that it will write directly to memory. Now, this doesn't necessarily mean each threads needs to read directly from memory. They can still read from their own processor caches. Having a thread call synchronized(this) ensures it pulls the value of the field(s) from memory and retrieve most up to date value.
If I recall correctly there is a Sin in Java threading known as double-checked locking.
It's been a while but its something like checking a value, then if it is true, going into a synchronized block and checking it again. Since it's been such a while I can't remember why it exact flaw. I remember it being related to the Java spec allowing implementations to reorder the execution of various statements in someway (and because most didn't it normally worked).
(It's advantage was minimizing having to go into synchronized blocks which is slow.)
I was looking over: http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
and came across:
A simple trick can be used to remove the synchronization that we've
added to each iteration of the "run loop." The synchronized block that
was added is replaced by a slightly more complex piece of code that
enters a synchronized block only if the thread has actually been
suspended:
if (threadSuspended) {
synchronized(this) {
while (threadSuspended)
wait();
}
}
Which feels a bit like double-checked locking, but I feel imp prob wrong since it's from official documentation.
Also the fact that it is a while loop seems a bit off.
So is that code evil? Or not?
Using the volatile keyword on the threadSuspended variable will give you the effect you need. The issue is that when multiple threads are accessing the same variable, there can be thread-local caching of the variable. The volatile keyword ensures that this caching does not occur.
Here is a post explaining further.
EDIT:
Regarding the while, since the purpose of the code is to wait until the thread is no longer suspended, I see no reason not to use a while.
Also, as mentioned in the comment, the line below the snippet you pasted mentions volatile, and the full code snippet a few lines beneath that declares threadSuspended as a volatile boolean.
No, this is not the double-checked locking pattern as no writes to shared variables are being done while the lock is held.
The main issue you might encounter is that changes of threadSuspended from false to true may not be noticed in quite as timely a fashion because of cache coherency or register caching issues. The register caching issues are the biggest problem (cache coherency eventually solves itself, though it may take a few microseconds), and depend greatly on the surrounding code and what the optimizer does.
If this is isolated code inside a function, it's not likely you'll have a register caching issue. If threadSuspended has been declared volatile you will also not have an issue as the optimizer will not register cache volatile things.
Two references about double-checked locking:
Java Concurrency in Practice, 16.2.4. Double-checked Locking
Effective Java, Second Edition, Item 71: Use lazy initialization judiciously
Regarding the while -- wait() is allowed to return spuriously -- that is, without anybody having called notify() on the object. This means that when wait() returns, it's probably, but not definitely, because someone set threadSuspended and then called notify(). The way you guard against this is by re-checking threadSuspended, which is what the while is there for.
My teacher in an upper level Java class on threading said something that I wasn't sure of.
He stated that the following code would not necessarily update the ready variable. According to him, the two threads don't necessarily share the static variable, specifically in the case when each thread (main thread versus ReaderThread) is running on its own processor and therefore doesn't share the same registers/cache/etc and one CPU won't update the other.
Essentially, he said it is possible that ready is updated in the main thread, but NOT in the ReaderThread, so that ReaderThread will loop infinitely.
He also claimed it was possible for the program to print 0 or 42. I understand how 42 could be printed, but not 0. He mentioned this would be the case when the number variable is set to the default value.
I thought perhaps it is not guaranteed that the static variable is updated between the threads, but this strikes me as very odd for Java. Does making ready volatile correct this problem?
He showed this code:
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready) Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
There isn't anything special about static variables when it comes to visibility. If they are accessible any thread can get at them, so you're more likely to see concurrency problems because they're more exposed.
There is a visibility issue imposed by the JVM's memory model. Here's an article talking about the memory model and how writes become visible to threads. You can't count on changes one thread makes becoming visible to other threads in a timely manner (actually the JVM has no obligation to make those changes visible to you at all, in any time frame), unless you establish a happens-before relationship.
Here's a quote from that link (supplied in the comment by Jed Wesley-Smith):
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. In particular:
Each action in a thread happens-before every action in that thread that comes later in the program's order.
An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.
A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.
A call to start on a thread happens-before any action in the started thread.
All actions in a thread happen-before any other thread successfully returns from a join on that thread.
He was talking about visibility and not to be taken too literally.
Static variables are indeed shared between threads, but the changes made in one thread may not be visible to another thread immediately, making it seem like there are two copies of the variable.
This article presents a view that is consistent with how he presented the info:
http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html
First, you have to understand a little something about the Java memory model. I've struggled a bit over the years to explain it briefly and well. As of today, the best way I can think of to describe it is if you imagine it this way:
Each thread in Java takes place in a separate memory space (this is clearly untrue, so bear with me on this one).
You need to use special mechanisms to guarantee that communication happens between these threads, as you would on a message passing system.
Memory writes that happen in one thread can "leak through" and be seen by another thread, but this is by no means guaranteed. Without explicit communication, you can't guarantee which writes get seen by other threads, or even the order in which they get seen.
...
But again, this is simply a mental model to think about threading and volatile, not literally how the JVM works.
Basically it's true, but actually the problem is more complex. Visibility of shared data can be affected not only by CPU caches, but also by out-of-order execution of instructions.
Therefore Java defines a Memory Model, that states under which circumstances threads can see consistent state of the shared data.
In your particular case, adding volatile guarantees visibility.
They are "shared" of course in the sense that they both refer to the same variable, but they don't necessarily see each other's updates. This is true for any variable, not just static.
And in theory, writes made by another thread can appear to be in a different order, unless the variables are declared volatile or the writes are explicitly synchronized.
Within a single classloader, static fields are always shared. To explicitly scope data to threads, you'd want to use a facility like ThreadLocal.
When you initialize static primitive type variable java default assigns a value for static variables
public static int i ;
when you define the variable like this the default value of i = 0;
thats why there is a possibility to get you 0.
then the main thread updates the value of boolean ready to true. since ready is a static variable , main thread and the other thread reference to the same memory address so the ready variable change. so the secondary thread get out from while loop and print value.
when printing the value initialized value of number is 0. if the thread process has passed while loop before main thread update number variable. then there is a possibility to print 0
#dontocsata
you can go back to your teacher and school him a little :)
few notes from the real world and regardless what you see or be told.
Please NOTE, the words below are regarding this particular case in the exact order shown.
The following 2 variable will reside on the same cache line under virtually any know architecture.
private static boolean ready;
private static int number;
Thread.exit (main thread) is guaranteed to exit and exit is guaranteed to cause a memory fence, due to the thread group thread removal (and many other issues). (it's a synchronized call, and I see no single way to be implemented w/o the sync part since the ThreadGroup must terminate as well if no daemon threads are left, etc).
The started thread ReaderThread is going to keep the process alive since it is not a daemon one!
Thus ready and number will be flushed together (or the number before if a context switch occurs) and there is no real reason for reordering in this case at least I can't even think of one.
You will need something truly weird to see anything but 42. Again I do presume both static variables will be in the same cache line. I just can't imagine a cache line 4 bytes long OR a JVM that will not assign them in a continuous area (cache line).