In java specification 17.3. Sleep and Yield, it says
It is important to note that neither Thread.sleep nor Thread.yield have any synchronization semantics.
This sentence is the point. If I replace Thread.sleep(100) by System.out.println("") in my test code below, the compiler always read iv.stop every time because System.out.println("") acquires a lock, check this question. Java specification says Thread.sleep does not have any synchronization semantics, so I wonder what makes compiler treat Thread.sleep(100) as same as System.out.println("").
My test code:
public class InfiniteLoop {
boolean stop = false;
public static void main(String[] args) throws InterruptedException {
final InfiniteLoop iv = new InfiniteLoop();
Thread t1 = new Thread(() -> {
while (!iv.stop) {
//uncomment this block of code, loop broken
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
System.out.println("done");
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
iv.stop = true;
});
t1.start();
t2.start();
}
}
As the comment above says, Thread.sleep() breaks the loop, this is different from the description of the Java specification: why?
Let's see what the docs actually says:
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 another thread changed the value of this.done.
See the highlighted word "free"? "free" means that the compiler can either read this.done once, or not. It's the compiler's choice. That's what "free" means. Your loop breaks because the compiler sees your code and thought "I am going to read iv.stop every time, even though I can read it just once."
In other words, it is not guaranteed to always break the loop. Your code behaves exactly as the docs say.
so I wonder what makes compiler treat Thread.sleep(100) as same as System.out.println("").
Well there is certainly nothing in the language definition that says that they are at all the same. Thread.sleep(...) does not cross any memory barriers while System.out.println(...) does. What you may be seeing is an artifact of how your threaded application is running on your architecture. Maybe the thread gets swapped out because of CPU contention which forces the cache memory to be flushed. If you ran this on a different OS or on hardware with more cores you would most likely not see sleep(...) do anything.
The difference here may also be a compiler optimization. The while loop with nothing in it might not be even checking the value of the stop field since the compiler knows that nothing is updating it inside the loop and it's not volatile. As soon as you add something that does thread state manipulation, it changes the generated code so that the field is then actually paid attention.
Ultimately, the problem is around the publishing of the boolean stop field between threads. The field should be marked as volatile to ensure it is properly shared. As you mentioned, when you call System.out.println(...) this goes in and out of a synchronized block which crosses memory barriers which effectively update the stop field.
Though the question is already answered I don't feel the other answers address the confusion in the question.
If we simplify the code to
while (!iv.stop) {
// do something ....
}
Then the compiler is free (as others have said) to read iv.stop only once. The important points are:
To force the compiler to enforce a re-read of iv.stop, it should be declared volatile.
Without volatile, the compiler may, or may not change whether it decides to re-read iv.stop as a result of changing the loop contents ("do something...") but that cannot be reliably predicted.
You can't infer anything special in this context about the fact that sleep doesn't use locking semantics
(The third point references what I believe to be the confusion in the question)
So with regards to the issue of println() vs sleep(): The fact that sleep doesn't use locking semantics is irrelevant; println doesn't use locking semantics either.
println implementation may use locking to ensure it's own thread-safety, but that fact is not visible in the scope of the calling code (ie your code). (As a side note, sleep implementation ultimately will use some sort of locking deep down in its implementation (in the native code).
From the API perspective, both sleep and println are static methods which take one parameter, so the compiler is likely to be affected the same way by them, with regards to how it performs optimisations in the surrounding code, but like I said you can't rely on that.
Related
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 faced the following code in our project:
synchronized (Thread.currentThread()){
//some code
}
I don't understand the reason to use synchronized on currentThread.
Is there any difference between
synchronized (Thread.currentThread()){
//some code
}
and just
//some code
Can you provide an example which shows the difference?
UPDATE
more in details this code as follows:
synchronized (Thread.currentThread()) {
Thread.currentThread().wait(timeInterval);
}
It looks like just Thread.sleep(timeInterval). Is it truth?
consider this
Thread t = new Thread() {
public void run() { // A
synchronized (Thread.currentThread()) {
System.out.println("A");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
}
};
t.start();
synchronized (t) { // B
System.out.println("B");
Thread.sleep(5000);
}
blocks A and B cannot run simultaneously, so in the given test either "A" or "B" output will be delayed by 5 secs, which one will come first is undefined
Although this is almost definitely an antipattern and should be solved differently, your immediate question still calls for an answer. If your entire codebase never acquires a lock on any Thread instance other than Thread.currentThread(), then indeed this lock will never be contended. However, if anywhere else you have
synchronized (someSpecificThreadInstance) { ... }
then such a block will have to contend with your shown block for the same lock. It may indeed happen that the thread reaching synchronized (Thread.currentThread()) must wait for some other thread to relinquish the lock.
Basically there is no difference between the presence and absence of the synchronized block. However, I can think of a situation that could give other meaning to this usage.
The synchronized blocks has an interesting side-effect of causing a memory barrier to be created by the runtime before entering and after leaving the block. A memory barrier is a special instruction to the CPU that enforces all variables that are shared between multiple threads to return their latest values. Usually, a thread works with its own copy of a shared variable, and its value is visible to this thread only. A memory barrier instructs the thread to update the value in a way so that the change is visible to the other threads.
So, the synchronized block in this case does not do any locking (as there will be no real case of lock and wait situation, at lest none I can think of)(unless the use-case mentioned in this answer is addressed), but instead it enforces the values of the shared fields to return their latest value. This, however, is true if the other places of the code that work with the variables in question also uses memory barriers (like having the same synchronized block around the update/reassignment operations). Still, this is not a solution for avoiding race conditions.
If you're interested, I recommend you to read this article. It is about memory barriers and locking in C# and the .NET framework, but the problem is similar for Java and the JVM (except for the behavior of volatile fields). It helped me a lot in understanding how threads, volatile fields and locks work in general.
One must take into account some serious considerations in this approach, that were mentioned in comments below this answer.
The memory barrier does not imply locking. The access will still be non-synchronized and a subject to race conditions and other potential issues one may encounter. The only benefit is the thread being able to read the latest values of the shared memory fields, without the use of locks. Some practices use similar approaches if the working thread only reads from values and it does only care for them to be the most present ones, while avoiding the overhead of locks - a use case could be a high-performance simultaneous data processing algorithm.
The approach above is unreliable. As per Holger's comment, the compiler could eliminate the lock statements when optimizing, as it could consider them unnecessary. This will also remove the memory barriers. The code then will not issue a lock, and it will not work as expected if a lock was meant to be used, or the purpose was to create a memory barrier.
The approach above is also unreliable because the runtime JVM can remove synchronization when it can prove the monitor will never be acquired by another thread, which is true of this construct if the code never synchronizes on another thread object which is not the current thread's thread object. So even if it works during testing on system A, it might fail under another JVM on system B. Even worse, the code could work for a while and then cease working as optimizations are applied.
The intentions of the code as it stays now are ambiguous, so one should use more explicit and expressive means to achieve its effect (see Marko Topolnik's comment for reference).
You are implementing a recursive mutex.
i.e. the same thread can enter the synchronisation block, but not other threads.
I am learning the usage of volatile in Java. Here is a sample code I read from many articles:
static volatile boolean shutdownRequested = false;
...
public void shutdown() { shutdownRequested = true; }
public void doWork() {
while (!shutdownRequested) {
// do stuff
}
}
I try this on my machine with and without "volatile", but they show no difference: they can both shutdown.
So what's wrong? Is there anything wrong with my code, or does it depend on the version of the Java compiler?
Addition: in many articles, they say this program without "volatile" will not successfully shutdown because this loop while (!shutdownRequested) will be optimized to while(true) by Java compiler if the value of the variable shutdownRequested is not changed inside the loop. But the result of my experiment does not stand for that.
I assume you mean you have a setup something like this:
final Worker theWorker = new Worker(); // the object you show code for
new Thread(new Runnable() {
public void run() {
theWorker.doWork();
}
}.start();
try {
Thread.sleep(1000L);
} catch(InterruptedException ie) {}
theWorker.shutdown();
And what you found is that the shutdown works even without volatile.
It's typically the case that this is true: non-volatile writes may be seen eventually. The important thing is that there is not a guarantee this needs to be the case and you can't rely on it. In practical use you may also find there is a small but noticeable delay without volatile.
Volatile provides a guarantee that writes are seen immediately.
Here's some code that might reproduce the HotSpot optimization we discussed in the comments:
public class HotSpotTest {
static long count;
static boolean shouldContinue = true;
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
public void run() {
while(shouldContinue) {
count++;
}
}
});
t.start();
do {
try {
Thread.sleep(1000L);
} catch(InterruptedException ie) {}
} while(count < 999999L);
shouldContinue = false;
System.out.println(
"stopping at " + count + " iterations"
);
try {
t.join();
} catch(InterruptedException ie) {}
}
}
Here's a quick review if you don't know what HotSpot is: HotSpot is the Java just-in-time compiler. After some fragment of code has run a certain number of times (from memory, 1000 for desktop JVM, 3000 for server JVM), HotSpot takes the Java bytecode, optimizes it, and compiles it to native assembly. HotSpot is one of the reasons Java is so lightning fast. In my experience, code recompiled by HotSpot can be easily 10x faster. HotSpot is also much more aggressive about optimization than a regular Java compiler (like javac or others made by IDE vendors).
So what I found is the join just hangs forever if you let the loop run long enough first. Note that count is not volatile by design. Making count volatile seems to foil the optimization.
From the perspective of the Java memory model it makes sense that as long as there is absolutely no memory synchronization HotSpot is allowed to do this. HotSpot knows there's no reason the update needs to be seen so it doesn't bother checking.
I didn't print the HotSpot assembly since that requires some JDK software I don't have installed but I'm sure if you did, you'd find the same thing the link you provided recalls. HotSpot does indeed seem to optimize while(shouldContinue) to while(true). Running the program with the -Xint option to turn HotSpot off results in the update being seen as well which also points to HotSpot as the culprit.
So, again, it just goes to show you can't rely on a non-volatile read.
Volatile is for threading. It basically tells the threads the variable can change anytime, so anytime it wants the variable it can't rely on a cached copy it must re read it and the update it after changing it
Volatile in many senses is due to the local caching that a processor can do on a per-thread basis.
for example, lest say we have a processor with 4 threads running your java program (albeit a massively simplified example since a processor would do WAY more than just this). Lets also assume that each of those 4 main threads have access to a local cache (not to be confused with a main processor cache). So, if you just made that variable static, and all 4 threads were reading from that variable, they could all potentially put that variable in their local cache. Alright, great, access time is improved, and everything is faster. So, at the moment we have the following situation:
Thread 1: has a local copy of the variable
Thread 2: has a local copy of the variable
Thread 3: '' '' '' '' '' '' ''
Thread 4: '' '' '' '' '' '' ''
Alright, now, lets say that Thread 1 goes in and changes the ACTUAL variable, not just the copy. Thread 1 knows about the change immediately, but threads 2-4 could still be working on the value of the old, cached version of the variable since they haven't checked for any updates yet.
Now, to fix this type of situation, you can attach the 'volatile' keyword to the variable, which essentially tells it to broadcast its new value to all of the threads in the program IMMEDIATELY so that any operations on all of the threads will have the exact same value. Of course, this does incur some overhead, so something that is volatile will be a touch slower if it is modified often. Since your program is not multi-threaded (that I can tell) you'll see little to no difference using volatile or not. It's simply a trivial (and pointless) extra 'command' for the variable in single-threaded environments.