Unexpected thread behavior. Visibility - java

I have the following code:
public static boolean turn = true;
public static void main(String[] args) {
Runnable r1 = new Runnable() {
public void run() {
while (true) {
while (turn) {
System.out.print("a");
turn = false;
}
}
}
};
Runnable r2 = new Runnable() {
public void run() {
while (true) {
while (!turn) {
System.out.print("b");
turn = true;
}
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
In class we've learned about "Visibility" problems that may occur when using un-synchronized code.
I understand that in order to save time, the compiler will decide the grab turn to the cache in the CPU for the loop, meaning that the thread will not be aware if the turn value was changed in the RAM because he doesn't check it.
From what I understand, I would expected the code to run like this:
T1 will see turn as true -> enter loop and print -> change turn to false -> gets stuck
T2 will think turn hasn't changed -> will get stuck
I would expect that if T1 will start before T2: only 'a' will be printed and both threads will run in an infinite loop without printing anything else
However, when I'm running the code sometimes I get a few "ababa...." before both threads will stuck.
What am I missing ?
EDIT:
The following code does what I expect it: the thread will run in a infinite loop:
public class Test extends Thread {
boolean keepRunning = true;
public void run() {
long count = 0;
while (keepRunning) {
count++;
}
System.out.println("Thread terminated." + count);
}
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
t.start();
Thread.sleep(1000);
t.keepRunning = false;
System.out.println("keepRunning set to false.");
}
}
How are they different from each other ?

When I run the code, sometimes I get a few "ababa...." before both threads will stuck.
I suspect that what is happening is that the behavior is changing when the code is JIT compiled. Before JIT compilation the writes are visible because the interpreter is doing write-throughs. After JIT compilation, either the cache flushes or the reads have been optimized away ... because the memory model allows this.
What am I missing ?
What you are missing is that you are expecting unspecified behavior to be consistent. It doesn't have to be. After all, it is unspecified! (This is true, even if my proposed explanation above is incorrect.)

The fact that turn isn't volatile doesn't mean that your code WILL break, just that it MIGHT break. For all we know, the thread could see false or true at any given moment. Caches could just be randomly flushed for no reason in particular, the thread could retain its cache, etc etc.
It could be because your code is experiencing side effects from System.out.print, which internally writes to a synchronized method:
521 private void write(String s) {
522 try {
523 synchronized (this) {
(Source - DocJar)
The memory effects of synchronized could be flushing the cache and therefore impact your code.
As #Stephen C said, it could also be the JIT, which might hoist the boolean check because it assumes that the value can't change due to another thread.
So out of the three different possibilities mentioned so far, they could all be factors to contribute to how your code behaves. Visibility is a factor, not a determiner.

Related

Thread.sleep behaviour with non-volatile boolean variable

According to the JLS 17 specification section 17.3:
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 another thread changed the value of this.done
I have tried to simulate this following example: 2 threads concurrently access the same boolean variable, the first thread using the shared boolean in while loop, and the second thread update the boolean value.
1.Code without Thread.sleep() inside the first thread:
public boolean done;
public void performTest() throws InterruptedException {
done = false;
new Thread(() -> {
System.out.println("Running Thread 1...");
int count = 0;
while (!done) {
count++;
}
System.out.println("Exiting thread...");
}).start();
Thread.sleep(100);
new Thread(() -> {
System.out.println("Thread 2 setting done to true");
done = true;
}).start();
}
-> This code would never terminated, because the done variable not declared as volatile
2.Now change the code to include Thread.sleep() inside while loop as mentioned in the JLS
public boolean done;
public void performTest() throws InterruptedException {
done = false;
new Thread(() -> {
System.out.println("Running Thread 1...");
int count = 0;
while (!done) {
count++;
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Exiting thread...");
}).start();
Thread.sleep(100);
new Thread(() -> {
System.out.println("Thread 2 setting done to true");
done = true;
}).start();
}
-> Now it successfully exists in the first thread.
So i am confused between this example and the JLS mentioned. Not sure what i am missing here.
Note: i also noticed that Venkat's also mentioned this example in one of his videos, and there is a blog post that explained this behavior, and it looks like there is something related to JIT optimization. What is really concerned me here is that this example is not like what is described in the JLS.
The reason that the code is broken in your example is because the JVM is free to use a cached version of done so that your loop would never end. When you have 'Thread.sleep()' in there, it is unlikely to happen, but it is still a possiblity. That means, you write some code and test it and it works great. Then you change an environment, or change a JVM and suddenly it is broken.
This is a poor benchmark, but it gives an idea.
public class VolatileTest implements Runnable{
boolean done = false;
public void run(){
long count = 0;
long start = System.nanoTime();
long end = Integer.MAX_VALUE;
while(!done){
count++;
if(count == end){
break;
}
//try{ Thread.sleep(0); } catch (Exception e){ break;}
}
System.out.println( System.nanoTime() - start + " with " + count + " iterations");
}
public static void main(String[] args) throws Exception{
VolatileTest vt = new VolatileTest();
new Thread(vt).start();
Thread.sleep(500);
vt.done = true;
}
}
Now there are 3 cases. 1st as written without any sleep/volatile.
650503733 with 2147483647 iterations
It took 650ms to complete Integer.MAX_VALUE iterations. note sometimes this
finishes faster than the 500ms I wait.
2nd case, volatile done.
499923823 with 1091070867 iterations
Now it never completes before vt.done is set to true.
3rd case. non-volatile with Thread.sleep
499905166 with 3031374 iterations
With the volatile version is 300 times faster than the Thread.sleep version. The non-volatile version is more intermittent in how fast it is but it is the fastest. I suspect due to when the JIT decides to cache done it gets a speed boost so to speak.
I'm not sure how to verify when it decides to cache the done variable, but I think that why JMH is necessary for these types of micro benchmarks.

When does a thread-locally cached variable makes consistent with "main memory" after being updated?

I am totally puzzled with the two samples.
public class VTest {
private static /*volatile*/ boolean leap = true;
public static void main(String[] args) throws InterruptedException {
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
while (leap) {
}
}
});
t2.start();
Thread.sleep(3000);
leap = false;
}
}
In this case, t2 is not able to stop, as leap was stored locally so that t2 can't access the leap updated in main thread.
public class VTest2 {
private static int m = 0;
public static void main(String[] args) throws InterruptedException {
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 10000; ++i) ++m;
}
});
t2.start();
for (int i = 0; i < 10000; ++i) ++m;
Thread.sleep(3000);
System.out.println(m);
}
}
But, in this case, the m is always be 20000, why isn't 10000?
Any answer will be appreciated.
It's not really a matter of "when". Because of the way that m is declared, the two threads have no reason to believe that it needs to consider the value in main memory.
Consider that ++m is not an atomic operation, but is rather:
A read
An increment
A write
Because the thread doesn't know it needs to read from or flush to main memory, there is no guarantee as to how it is executed:
Perhaps it reads from main memory each time, and flushes to main memory each time
Perhaps it reads from main memory just once, and doesn't flush to main memory when it writes
Perhaps it reads from/writes to main memory on some iterations of the loop
(...many other ways)
So, essentially, the answer is that there is no guarantee that the value is read from or written to main memory, ever.
If you declare m as volatile, that gives you some guarantees: that m is definitely read from main memory, and definitely flushed to main memory. However, because ++m isn't atomic, there is no guarantee that you get 20000 at the end (it's possible it could be 2, at worst), because the work of the two threads can intersperse (e.g. both threads read the same value of m, increment it, and both write back the same value m+1).
To do this correctly, you need to ensure that:
++m is executed atomically
The value is guaranteed to be visible.
The easiest way of doing this would be to use an AtomicInteger instead; however, you could mutually synchronize the increments:
synchronized (VTest2.class) {
++m;
}
You then also need to synchronize the final read, in order to ensure you are definitely seeing the last value written by t2:
synchronized (VTest2.class) {
System.out.println(m);
}
In this case, t2 is not able to stop, as leap was stored locally so that t2 can't access the leap updated in main thread.
That's not really the case: the leap variable was not stored "locally" by the thread. It's still a shared static variable. However, because it is not marked as volatile, and there is no synchronization happening whatsoever, the JVM (the JIT in particular) is free to do optimization to avoid loading it. I believe in this case it is removing the check on the variable.
Note: The second code incrementing m is not thread-safe: try increasing the loop to millions to test that, it will almost never match the expected sum.

Why the program without 'volatile' works as 'volatile'?

As typed below, the program has a shared var flag without volatile:
public class T {
public static void main(String[] args) {
TT jump = new TT(() -> {
while (true) {
if (TT.flag) {
System.out.println("jump");
break;
}
}
});
jump.start();
new TT(() -> {
TT.flag = true; // P1
LocalDateTime t1 = LocalDateTime.now();
while (true) {
if (Duration.between(t1, LocalDateTime.now()).toMillis() > 100) {
break;
}
}
System.out.println("flag");
}).start();
}
static class TT extends Thread {
public static boolean flag = false;
public TT(Runnable o) {
super(o);
}
}
}
The program always returns normally. So I believe the line of P1 ,where the flag was set to true, updated flag in other threads.
But why? flag is not volatile, why its value was updated immediately? Always!
But why? flag is not volatile, why its value was updated immediately? Always!
You are simply lucky; or unlucky, depending upon your perspective. I tried this on Ideone, and found that it timed out rather than terminating normally.
Remember: not being able to observe a concurrency bug is not the same as an absence of a concurrency bug.
The most sure you can be about code is when you can prove, according to the specification, that there are no bugs. That doesn't mean that the code will then work correctly; it just means that the problems are in the JVM implementation.
In particulary, you can't prove that this code will work correctly, because there is no happens-before relationship between the write to flag in the second thread, and the read in the first thread. Adding volatile creates this guarantee, because a volatile write happens before a volatile read.
That's not to say it will never work without volatile, it's just not guaranteed: a JVM only has to flush a thread's cached values at least as often as the spec requires, but can do it more often, or indeed not cache values at all.

Thread Signalling Sequence

In the below code I have implemented inter Thread communication using wait() -notify() and it is giving me expected output.
expected Output : 123456789 Actual output : 123456789
My question is , is there any guarantee that always 'Main Thread' will get the first chance to execute, since Thread scheduling depends on jvm. And if 'child thread' gets the first chance, the notify() signal will miss and the 'main Thread ' will wait forever. How can I confirm that 'Main thread' will execute first always. Also please confirm if the below code can be improved.
package com.test.Thread;
public class ThreadExample1 {
public static void main(String[] args) throws InterruptedException{
ThreadChild1 lockingObj = new ThreadChild1();
lockingObj .start();
synchronized(lockingObj ){
for(int i=1;i<10;i++){
System.out.println("Main "+i);
}
lockingObj.wait();
System.out.println("Main got notified");
}
}
}
class ThreadChild1 extends Thread{
public void run(){
synchronized(this){
for(int i=1;i<10;i++){
System.out.println("Child "+i);
}
this.notify();
}
}
}
Your code is wrong for the reason that you mentioned yourself: you can't be sure which thread goes first.
There are other things that could go wrong - wait can wake up without a notify.
You can read about it in the Javadoc for the wait method, which also explains what you should do:
As in the one argument version, interrupts and spurious wakeups are
possible, and this method should always be used in a loop:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
In your code, you can solve it with a boolean variable that expresses the condition "I was notified":
public class ThreadExample1 {
public static void main(String[] args) throws InterruptedException {
ThreadChild1 lockingObj = new ThreadChild1();
lockingObj.start();
synchronized (lockingObj) {
for(int i = 1; i < 10; i++) {
System.out.println("Main " + i);
}
while (!lockingObj.haveNotified) {
lockingObj.wait();
}
System.out.println("Main got notified");
}
}
}
class ThreadChild1 extends Thread{
private boolean haveNotified;
public void run(){
synchronized (this) {
for (int i = 1; i < 10; i++) {
System.out.println("Child " + i);
}
haveNotified = true;
this.notify();
}
}
}
While this works correctly on your system, it is not a guranty as your suspicion might become true on a different system. Threading behavior is verry difficult/impossible to predict. Therefore I like to think in worst case scenarios, and if I can come up with a possible breaking situation (as you just described one) I simply redesign to make sure it will work.
A nice trick to test your code is to suspend/pause threads on critical moments by either adding a breakpoint in your IDE, adding a verry time consuming task/call if possible (not failsafe), or by fysically pausing the thread(not always ideal). Besides Im sure there is are libraries to expand on this type of tesing.
I hope this helps you a bit in the right direction.

Volatile in java

As far as I know volatile write happens-before volatile read, so we always will see the freshest data in volatile variable. My question basically concerns the term happens-before and where does it take place? I wrote a piece of code to clarify my question.
class Test {
volatile int a;
public static void main(String ... args) {
final Test t = new Test();
new Thread(new Runnable(){
#Override
public void run() {
Thread.sleep(3000);
t.a = 10;
}
}).start();
new Thread(new Runnable(){
#Override
public void run() {
System.out.println("Value " + t.a);
}
}).start();
}
}
(try catch block is omitted for clarity)
In this case I always see the value 0 to be printed on console. Without Thread.sleep(3000); i always see value 10. Is this a case of happens-before relationship or it prints 'value 10' because thread 1 starts a bit earlier thread 2?
It would be great to see the example where the behaviour of code with and without volatile variable differs in every program start, because the result of code above depends only(at least in my case) on the order of threads and on thread sleeping.
You see the value 0 because the read is executed before the write. And you see the value 10 because the write is executed before the read.
If you want to have a test with more unpredictable output, you should have both of your threads await a CountDownLatch, to make them start concurrently:
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable(){
#Override
public void run() {
try {
latch.await();
t.a = 10;
}
catch (InterruptedException e) {
// end the thread
}
}
}).start();
new Thread(new Runnable(){
#Override
public void run() {
try {
latch.await();
System.out.println("Value " + t.a);
}
catch (InterruptedException e) {
// end the thread
}
}
}).start();
Thread.sleep(321); // go
latch.countDown();
The happens-before really has to do with a write happens before any subsequent read. If the write has not occurred yet there really is no relationship. Since the write-thread is sleeping the read is executed before the write occurs.
To observe the relationship in action you can have two variables one that is volatile and one that is not. According to the JMM it says the write to a non-volatile variable before a volatile write happens before the volatile read.
For instance
volatile int a = 0;
int b = 0;
Thread 1:
b = 10;
a = 1;
Thread 2:
while(a != 1);
if(b != 10)
throw new IllegalStateException();
The Java Memory Model says that b should always equal 10 because the non-volatile store occurs before the volatile store. And all writes that occur in one thread before a volatile store happen-before all subsequent volatile loads.
I've re-phrased (changes in bold fonts) the happens-before rule mentioned in the first sentence of your question as below so that it could be understood better -
"write of the value of a volatile variable to the main memory happens-before any subsequent read of that varible from main memory".
Also it is important to note that volatile writes/reads always
happen to/from the main memory and NOT to/from any local memory
resources like registers, processor caches etc.
The practical implication of the above happens-before rule is that all the threads that share a volatile variable will always see consistent value of that variable. No two threads see different values of that variable at any given point of time.
On the contrary, all the threads that share a non-volatile variable may see different values at any given point of time unless it is not synchronized by any other kind of synchronization mechanisms such as synchronized block/method, final keyword etc.
Now coming back to your question on this happens-before rule, i think u've slightly misunderstood that rule. The rule does not dictate that a write code should always happen (execute) before a read code. Rather it dictates that if a write code (volatile variable write) were to be executed in one thread before a read code in another thread then the effect of the write code should have happened in the main memory before the read code is executed so that the read code can see the latest value.
In the absence of volatile (or any other synchronization mechanisms), this happens-before is not mandatory, and hence a reader thread might see a stale value of non-volatile variable even though it has been recently written by a different writer thread. Because the writer thread can store the value in its local copy and need not have flushed the value to the main memory.
Hope the above explanation is clear :)
don't stick to the term 'happens-before'. it is a relation between events, used by jvm during R/W operations scheduling. at this stage it won't help you understand the volatile. the point is: jvm orders all R/W operations. jvm can order however it wants (of course obeying to all synchronize, lock, wait etc).
and now: if variable is volatile then any read operation will see the result of latest write operation. if variable is not volatile then it is not guaranteed (in different threads). that's all
piotrek is right, here is the test:
class Test {
volatile int a = 0;
public static void main(String ... args) {
final Test t = new Test();
new Thread(new Runnable(){
#Override
public void run() {
try {
Thread.sleep(3000);
} catch (Exception e) {}
t.a = 10;
System.out.println("now t.a == 10");
}
}).start();
new Thread(new Runnable(){
#Override
public void run() {
while(t.a == 0) {}
System.out.println("Loop done: " + t.a);
}
}).start();
}
}
with volatile: it will always end
without volatile: it will never end
From wiki:
In Java specifically, a happens-before relationship is a guarantee that memory written to by statement A is visible to statement B, that is, that statement A completes its write before statement B starts its read.
So if thread A write t.a with value 10 and thread B tries to read t.a some later, happens-before relationship guarantees that thread B must read value 10 written by thread A, not any other value. It's natural, just like Alice buys milk and put them into fridge then Bob opens fridge and sees the milk. However, when computer is running, memory access usually doesn't access memory directly, that's too slow. Instead, software get the data from register or cache to save time. It loads data from memory only when cache miss happens. That the problem happens.
Let's see the code in the question:
class Test {
volatile int a;
public static void main(String ... args) {
final Test t = new Test();
new Thread(new Runnable(){ //thread A
#Override
public void run() {
Thread.sleep(3000);
t.a = 10;
}
}).start();
new Thread(new Runnable(){ //thread B
#Override
public void run() {
System.out.println("Value " + t.a);
}
}).start();
}
}
Thread A writes 10 into value t.a and thread B tries to read it out. Suppose thread A writes before thread B reads, then when thread B reads it will load the value from the memory because it doesn't cache the value in register or cache so it always get 10 written by thread A. And if thread A writes after thread B reads, thread B reads initial value (0). So this example doesn't show how volatile works and the difference. But if we change the code like this:
class Test {
volatile int a;
public static void main(String ... args) {
final Test t = new Test();
new Thread(new Runnable(){ //thread A
#Override
public void run() {
Thread.sleep(3000);
t.a = 10;
}
}).start();
new Thread(new Runnable(){ //thread B
#Override
public void run() {
while (1) {
System.out.println("Value " + t.a);
}
}
}).start();
}
}
Without volatile, the print value should always be initial value (0) even some read happens after thread A writes 10 into t.a, which violate the happen-before relationship. The reason is compiler optimizes the code and save the t.a into register and every time it will use the register value instead of reading from cache memory, of course which much faster. But it also cause the happen-before relationship violation problem because thread B can't get the right value after others update it.
In the above example, volatile write happens-before volatile read means that with volatile thread B will get the right value of t.a once after thread A update it. Compiler will guarantee every time thread B reads t.a, it must read from cache or memory instead of just using register's stale value.

Categories

Resources