I hava following code to test volatile. bEnd
and nCount
are defined volatile.
nCount = 0, bEnd = false
The Writer thread will set
nCount = 100, bEnd = true
The Reader thread read these viriables and print them. Base on the Java Happens-before order, in my opinion, volatile ensures nCount = 100 when bEnd = true. But sometimes the program print this:
main thread done.
thread Reader running ...
thread Writer running ...
SharedData nCount = 0, bEnd = false
thread Writer bEnd = true
thread Reader nCount = 0, bEnd = true
thread Reader nCount = 100, bEnd = true
thread Reader nCount = 100, bEnd = true
thread Reader done.
How can the Reader get "nCount = 0, bEnd = true" ???
The following code running on windows10, jdk1.8.0_131
public class HappensBeforeWithVolatile {
public static void main(String[] args) {
Thread threadWriter = new Thread(new Writer());
Thread threadReader = new Thread(new Reader());
threadWriter.start();
threadReader.start();
System.out.println("main thread done.");
}
}
class Writer implements Runnable {
@Override
public void run() {
System.out.println("thread Writer running ...");
SharedData.nCount = 100;
// System.out.println("thread Writer nCount = 100");
SharedData.bEnd = true;
System.out.println("thread Writer bEnd = true");
}
}
class Reader implements Runnable {
@Override
public void run() {
System.out.println("thread Reader running ...");
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
if (SharedData.nCount == 0 && SharedData.bEnd) {
System.out.println("thread Reader CODE REORDER !!!");
}
System.out.println("thread Reader nCount = " + SharedData.nCount + ", bEnd = " + SharedData.bEnd);
System.out.println("thread Reader done.");
}
}
class SharedData {
volatile public static boolean bEnd = false;
volatile public static int nCount = 0;
static {
System.out.println("SharedData nCount = " + nCount + ", bEnd = " + bEnd);
}
}
volatile ensures nCount = 100 when bEnd = true
Technologically, yes. But the reader did not read them atomically. So it might print nCount = 0 and bEnd = true
.
Here is an example:
nCount 0
nCount = 100
bEnd = true
thread Writer bEnd = true
bEnd true
Your entire example is a bit flawed btw. To test that happens-before, you need to test subsequent actions, that is make bEnd
volatile and nCount
not a volatile, then simplify your example as:
static class Reader implements Runnable {
@Override
public void run() {
while (true) {
if (SharedData.bEnd) {
System.out.println(SharedData.nCount);
break;
} else {
System.out.println("Not yet seen as true");
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
}
}
}
}
static class Writer implements Runnable {
@Override
public void run() {
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
SharedData.nCount = 100;
SharedData.bEnd = true;
}
}
That will output 100
, always (in this case at least). The correct explanation would be that if a Reader
Thread sees the update of the Write
thread of a volatile variable, it will see everything that was done before that, thus 100
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With