volatile是一个特殊的修饰符,只有成员变量才能使用它。在Java并发程序缺少同步类的情况下,多线程对成员变量的操作对其它线程是透明的。volatile变量可以保证下一个读取操作会在前一个写操作之后发生,就是上一题的volatile变量规则。
前言:
在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。
volatile会保证变量只在main 中改变。并及时share给其它线程。
一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。
正文:
How Volatile in Java works? Example of volatile keyword in Java
How to use Volatile keyword in Java
What is volatile variable in Java and when to use Volatile variable in Java is famous multi-threading interview question in Java interviews. Though many programmer knows what is a volatile variable but they fail on second part i.e. where to use volatile variable in Java as its not common to have clear understanding and hands-on on volatile in Java. In this tutorial we will address this gap by providing simple example of volatile variable in Java and discussing some when to use Volatile variable in Java. Any way Volatile keyword in Java is used as an indicator to Java compiler and Thread that do not cache value of this variable and always read it from main memory. So if you want to share any variable in which read and write operation is atomic by implementation e.g. read and write in int or boolean variable you can declare them as volatile variable. From Java 5 along with major changes like Autoboxing, Enum, Generics and Variable arguments , Java introduces some change in Java Memory Model (JMM), Which guarantees visibility of changes made by one thread to another also as "happens-before" which solves the problem of memory writes that happen in one thread can "leak through" and be seen by another thread. Java volatile keyword cannot be used with method or class and it can only be used with variable. Java volatile keyword also guarantees visibility and ordering , after Java 5 write to any volatile variable happens before any read into volatile variable. By the way use of volatile keyword also prevents compiler or JVM from reordering of code or moving away them from synchronization barrier.
YOL翻译
Java中的 volatile 变量是什么?何时使用volatile ?,在 Java 多线程的面试问题常见。
虽然很多程序员都知道什么是 volatile 变量,但他们对第二个问题就晕菜了,Java中也没有明确说明。在本教程中,我们将举例说明这个问题。 在 Java 中,Volatile在 Java 编译器和线程不缓存此变量的值,总是从主存读取它。所以如果你想要分享的任何原子的变量上的读和写操作,执行如读取和写入 int 或布尔值的变量,你可以将它们声明为 volatile 变量。从Java 5 开始,伴随着自动装箱、 枚举、 泛型和变量参数等主要的变化,Java介绍了一些 Java 内存模型 (JMM:http://ifeve.com/tag/jmm/)中的变化,它保证到另一个线程所做的更改可见性的一些变化也让其它线程有了偏序的问题(YOL注,请阅读JMM知识),这解决了发生在一个线程中的内存写入被泄漏,并被其它线程看见。Java volatile 关键字不能用于方法或类,它只可以用于变量。Java volatile 关键字也保证可视化和顺序性,Java 5 写入任何 volatile 变量后会发生以前任何读到 volatile 变量。顺便说一下使用 volatile 关键字还可以防止编译器或 JVM 中的代码重新排序或把他们从同步barrier中移除。
Volatile variable Example in Java
To Understand example of volatile keyword in java let’s go back to Singleton pattern in Java and see double checked locking in Singleton with Volatile and without volatile keyword in java.
[crayon-56579710312ff802293948/]
If you look at the code carefully you will be able to figure out:
1) We are only creating instance one time
2) We are creating instance lazily at the time of first request comes.
If we do not make _instance variable volatile then Thread which is creating instance of Singleton is not able to communicate other thread, that instance has been created until it comes out of the Singleton block, so if Thread A is creating Singleton instance and just after creation lost the CPU, all other thread will not be able to see value of _instance as not null and they will believe its still null.
Why? because reader threads are not doing any locking and until writer thread comes out of synchronized block, memory will not be synchronized and value of _instance will not be updated in main memory. With Volatile keyword in Java this is handled by Java himself and such updates will be visible by all reader threads.
So in Summary apart from synchronized keyword in Java, volatile keyword is also used to communicate content of memory between threads.
Let’s see another example of volatile keyword in Java
most of the time while writing game we use a variable bExit to check whether user has pressed exit button or not, value of this variable is updated in event thread and checked in game thread , So if we don't use volatile keyword with this variable , Game Thread might miss update from event handler thread if its not synchronized in java already. volatile keyword in java guarantees that value of volatile variable will always be read from main memory and "happens-before" relationship in Java Memory model will ensure that content of memory will be communicated to different threads.
private boolean bExit;
while(!bExit) {
checkUserPosition();
updateUserPosition();
}
In this code example One Thread (Game Thread) can cache the value of "bExit" instead of getting it from main memory every time and if in between any other thread (Event handler Thread) changes the value; it would not be visible to this thread. Making boolean variable "bExit" as volatile in java ensures this will not happen.
When to use Volatile variable in Java
One of the most important thing in learning of volatile keyword is understanding when to use volatile variable in Java. Many programmer knows what is volatile variable and How does it work but they never really used volatile for any practical purpose. Here are couple of example to demonstrate when to use Volatile keyword in Java:
1) You can use Volatile variable if you want to read and write long and double variable atomically. long and double both are 64 bit data type and by default writing of long and double is not atomic and platform dependence. Many platform perform write in long and double variable 2 step, writing 32 bit in each step, due to this its possible for a Thread to see 32 bit from two different write. You can avoid this issue by making long and double variable volatile in Java.
2) Volatile variable can be used as an alternative way of achieving synchronization in Java in some cases, like Visibility. with volatile variable its guaranteed that all reader thread will see updated value of volatile variable once write operation completed, without volatile keyword different reader thread may see different values.
3) volatile variable can be used to inform compiler that a particular field is subject to be accessed by multiple threads, which will prevent compiler from doing any reordering or any kind of optimization which is not desirable in multi-threaded environment. Without volatile variable compiler can re-order code, free to cache value of volatile variable instead of always reading from main memory. like following example without volatile variable may result in infinite loop
private boolean isActive = thread;
public void printMessage(){
while(isActive){
System.out.println("Thread is Active");
}
}
without volatile modifier its not guaranteed that one Thread see the updated value of isActive from other thread. compiler is also free to cache value of isActive instead of reading it from main memory in every iteration. By making isActive a volatile variable you avoid these issue.
4) Another place where volatile variable can be used is to fixing double checked locking in Singleton pattern. As we discussed in Why should you use Enum as Singleton that double checked locking was broken in Java 1.4 environment.
Important points on Volatile keyword in Java
- volatilekeyword in Java is only application to variable and using volatile keyword with class and method is illegal.
- volatilekeyword in Java guarantees that value of volatile variable will always be read from main memory and not from Thread's local cache.
- In Java reads and writes areatomicfor all variables declared using Java volatile keyword (including long and double variables).
- Using Volatilekeywordin Java on variables reduces the risk of memory consistency errors, because any write to a volatile variable in Java establishes a happens-before relationship with subsequent reads of that same variable.
- From Java 5 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 in Java, it sees not just the latest change to the volatile variable but also the side effects of the code that led up the change.
- Reads and writes are atomic for reference variables are for most primitive variables (all types except long and double) even without use of volatilekeywordin Java.
- An access to a volatile variable in Java never has chance to block, since we are only doing a simple read or write, so unlike a synchronized block we will never hold on to any lock or wait for anylock.
- Java volatile variable that is an object reference may be null.
- Java volatilekeyworddoesn't means atomic, its common misconception that after declaring volatile ++ will be atomic, to make the operation atomic you still need to ensure exclusive access using synchronized method or block in Java.
- If a variable is not shared between multiple threadsno need to use volatilekeyword with that variable.
- Volatile keyword in Java is a field modifier, while synchronized modifies code blocks and methods.
- Synchronized obtains and releases lock on monitor’s Java volatile keyword doesn't require that.
- Threads in Java can be blocked for waiting any monitor in case of synchronized, that is not the case with volatile keyword in Java.
- Synchronized method affects performance more than volatile keyword in Java.
- Since volatile keyword in Java only synchronizes the value of one variable between Thread memory and"main"memory while synchronized synchronizes the value of all variable between thread memory and "main" memory and locks and releases a monitor to boot. Due to this reason synchronized keyword in Java is likely to have more overhead than volatile.
- You can not synchronize on null object but your volatile variable in java could be null.
- From Java 5 Writing into a volatile field has the same memory effect as a monitor release, and reading from a volatile field has the same memory effect as a monitor acquire