I am studying Java Thread, and the keyword volatile
confuses me when I analyse the following code modified from Example 8.3.1.4
public class Volatile {
public static void main(String[] args){
MyRunnable1 myRunnable1 = new MyRunnable1();
MyRunnable2 myRunnable2 = new MyRunnable2();
Thread t1 = new Thread(myRunnable1);
Thread t2 = new Thread(myRunnable2);
t1.start();
t2.start();
}
}
class MyRunnable1 implements Runnable{
public void run(){
while(true){
Test1.one();
}
}
}
class MyRunnable2 implements Runnable{
public void run(){
while(true){
Test1.two();
}
}
}
class Test1{
static volatile int i = 0;
static volatile int j = 0;
static void one(){
i ++;
j ++;
}
static void two(){
System.out.println("i = " + i + " j = " + j);
}
}
An output segment :
i = 60778110 j = 60778116
i = 60778402 j = 60778407
i = 60778630 j = 60778636
i = 60779062 j = 60779079
i = 60779492 j = 60779497
i = 60779784 j = 60779789
i = 60780161 j = 60780169
i = 60780625 j = 60780632
i = 60780936 j = 60780942
My thought is that because of the volatile
, the i ++
happens before j ++
, their initial values are zero and the modified values will be flushed to the main memory immediately, so anytime the i
thread t2
sees should be greater than j
. However the output shows the i
is always lower than j
.
Then I modify the two
function as follow:
static void two(){
System.out.println("j = " + j + " i = " + i);
}
The change is that j
outputs prior to i
, then output segment as follow:
j = 47324409 i = 47324412
j = 47324587 i = 47324593
j = 47324808 i = 47324813
j = 47324991 i = 47324996
j = 47325193 i = 47325196
j = 47325347 i = 47325353
It surprises me that j
is always lower than i
.
My thought is that the j
is lower because it is connected first and after a while the i
is connected, during the time gap the one
function executes which causes i
increased.
So the first connected value will be lower than the second connected one, is it right? Thanks in advance!
Java and the JVM provide many ways to control memory order, and the volatile keyword is one of them. In this article, we'll focus on this foundational but often misunderstood concept in the Java language – the volatile keyword.
When a variable is not shared between multiple threads, you do not need to use the volatile keyword with that variable. Volatile keyword is not a substitute of synchronized keyword, but it can be used as an alternative in certain cases. There are the following differences are as follows:
The volatile variable that is an object reference may be null. When a variable is not shared between multiple threads, you do not need to use the volatile keyword with that variable. Volatile keyword is not a substitute of synchronized keyword, but it can be used as an alternative in certain cases.
If you do not use volatile variable compiler can reorder the code, free to write in cache value of volatile variable instead of reading from the main memory. You can use the volatile keyword with variables. Using volatile keyword with classes and methods is illegal.
You suppose right. The difference comes from the fact that the argument to the println
call is built in 3 steps:
and in the time when Runnable2 does this, especially after step1 and before the final print, Runnable2 is busy incrementing the values. And that leads to the behaviour you see.
This is no problem of volatile. If you want i and j in sync, you must synchronize the methods of class Test1.
Actually, volatile
simply prevents threads from caching a value, but instead forcing a "write-through" and "read-through":
If a variable is cached by one thread and updated by another, the value might never change for the first thread, because due to Java's caching policy, it is not required to refresh its caches.
So whenever you have multiple threads accessing and changing a primitive resource (like int, boolean, or the reference-type reference value itself) you should use volatile.
Which in itself does not mean that volatile actually makes variable access thread-safe!
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