https://wiki.sei.cmu.edu/confluence/display/java/CON50-J.+Do+not+assume+that+declaring+a+reference+volatile+guarantees+safe+publication+of+the+members+of+the+referenced+object
https://stackoverflow.com/questions/7075517/do-i-need-volatile-for-variables-of-reference-types-too
http://tutorials.jenkov.com/java-concurrency/volatile.html
https://javax0.wordpress.com/2016/09/21/final-volatile/
Years ago when I last time demonstrated the multi-thread capability Java was still 32-bit, or at least there was 32-bit Java available. On 32 bits you could concurrently increment long variables and because the lower and upper 32 bits were handled in different processor shift there was a chance that two threads garbled some way the non-volatile variable. Now with Java 9 this is not the case. Now Java is 64-bit and I had to demonstrate the need for a volatile on 64-bit before anyone comes up the stupid idea that it was only needed for 32-bit
https://stackoverflow.com/questions/106591/do-you-ever-use-the-volatile-keyword-in-java
TODO
https://wiki.sei.cmu.edu/confluence/display/java/CON50-J.+Do+not+assume+that+declaring+a+reference+volatile+guarantees+safe+publication+of+the+members+of+the+referenced+object
http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html
http://javarevisited.blogspot.com/2017/01/can-we-make-array-volatile-in-java.html
https://dzone.com/articles/3-tips-for-volatile-fields-in-java
Use Volatile Fields for Reading and Locks for Writing
java.util.concurrent.CopyOnWriteArrayList's get and set methods are an example of this tip:
https://wxx5433.gitbooks.io/interview-preparation/content/part_i_basics/java/java_volatile_keyword.html
http://www.geeksforgeeks.org/volatile-keyword-in-java/
volatile variable in Java is a special variable which is used to signal threads, compiler that this particular variables values is going to be updated by multiple thread inside Java application. By making a variable volatile using volatile keyword in Java, application programmer ensures that its value should always been read from main memory and thread should not used cached value of that variable from there own stack.
From JDK5 on, volatile variable also guarantees "happens-before" relationship, which means not only other thread has visibility of latest value of volatile variable but also all the variable seen by the thread which has updated value of volatile variable before this threads sees it.
When to use Volatile variable in Java
1) Any variable which is shared between multiple threads should be made variable, in order to ensure that all thread must see latest value of volatile variable.
2) A signal to compiler and JIT to ensure that compiler does not change ordering or volatile variable and moves them out of synchronized context.
3) You want to save cost of synchronization as volatile variables are less expensive than synchronization.
http://www.javacodegeeks.com/2014/07/making-operations-on-volatile-fields-atomic.html
重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境。
编译期重排序
编译期重排序的典型就是通过调整指令顺序,在不改变程序语义的前提下,尽可能减少寄存器的读取、存储次数,充分复用寄存器的存储值。
假设第一条指令计算一个值赋给变量A并存放在寄存器中,第二条指令与A无关但需要占用寄存器(假设它将占用A所在的那个寄存器),第三条指令使用A的值且与第二条指令无关。那么如果按照顺序一致性模型,A在第一条指令执行过后被放入寄存器,在第二条指令执行时A不再存在,第三条指令执行时A重新被读入寄存器,而这个过程中,A的值没有发生变化。通常编译器都会交换第二和第三条指令的位置,这样第一条指令结束时A存在于寄存器中,接下来可以直接从寄存器中读取A的值,降低了重复读取的开销。
Java存储模型中的重排序
在Java存储模型(Java Memory Model, JMM)中,重排序是十分重要的一节,特别是在并发编程中。JMM通过happens-before法则保证顺序执行语义,如果想要让执行操作B的线程观察到执行操作A的线程的结果,那么A和B就必须满足happens-before原则,否则,JVM可以对它们进行任意排序以提高程序性能。
volatile关键字可以保证变量的可见性,因为对volatile的操作都在Main Memory中,而Main Memory是被所有线程所共享的,这里的代价就是牺牲了性能,无法利用寄存器或Cache,因为它们都不是全局的,无法保证可见性,可能产生脏读。
volatile还有一个作用就是局部阻止重排序的发生,对volatile变量的操作指令都不会被重排序,因为如果重排序,又可能产生可见性问题。
在保证可见性方面,锁(包括显式锁、对象锁)以及对原子变量的读写都可以确保变量的可见性。但是实现方式略有不同,例如同步锁保证得到锁时从内存里重新读入数据刷新缓存,释放锁时将数据写回内存以保数据可见,而volatile变量干脆都是读写内存。
http://www.blogjava.net/aoxj/archive/2012/06/16/380926.html
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility
http://javarevisited.blogspot.kr/2015/10/133-java-interview-questions-answers-from-last-5-years.html
Multithreading, Concurrency and Thread basics Questions
1) Can we make array volatile in Java?
Yes, you can make an array volatile in Java but only the reference which is pointing to an array, not the whole array. What I mean, if one thread changes the reference variable to points to another array, that will provide volatile guarantee, but if multiple threads are changing individual array elements they won't be having happens before guarantee provided by volatile modifier.
2) Can volatile make a non-atomic operation to atomic?
One example I have seen is having a long field in your class. If you know that a long field is accessed by more than one thread e.g. a counter, a price filed or anything, you better make it volatile. Why? because reading to a long variable is not atomic in Java and done in two steps, If one thread is writing or updating long value, it's possible for another thread to see half value (fist 32-bit). While reading/writing a volatile long or double (64 bit) is atomic.
3) What are practical uses of volatile modifier?
One of the practical use of volatile variable is to make reading double and long atomic. Both double and long are 64-bit wide and they are read in two parts, first 32-bit first time and next 32-bit second time, which is non-atomic but volatile double and long read is atomic in Java. Another use of volatile variable is to provide a memory barrier, just like it is used inDisrupter framework. Basically, Java Memory model inserts a write barrier after you write to volatile variable and a read barrier before you read it. Which means, if you write to volatile field then its guaranteed that any thread accessing that variable will see the value you wrote and anything you did before doing that write into the thread is guaranteed to have happened and any updated data values will also be visible to all threads, because the memory barrier flushed all other writes to the cache.
4) What guarantee volatile variable provides? (answer)
volatile variables provide the guarantee about ordering and visibility e.g. volatile assignment cannot be re-ordered with other statements but in the absence of any synchronization instruction compiler, JVM or JIT are free to reorder statements for better performance. volatile also provides the happens-before guarantee which ensure changes made in one thread is visible to others. In some cases volatile also provide atomicity e.g. reading 64-bit data types like long and double are not atomic but read of volatile double or long is atomic.
Read full article from What is volatile variable in Java - When to use | Java67
https://stackoverflow.com/questions/7075517/do-i-need-volatile-for-variables-of-reference-types-too
http://tutorials.jenkov.com/java-concurrency/volatile.html
The Java
volatile
keyword is used to mark a Java variable as "being stored in main memory". More precisely that means, that every read of a volatile variable will be read from the computer's main memory, and not from the CPU cache, and that every write to a volatile variable will be written to main memory, and not just to the CPU cache.
JDK source code is one of the best ways to answers confusions like this. If you look at the code in AtomicReference, it uses a volatie variable for object storage.
private volatile V value;
So, obviously if you are going to just use get() and set() on AtomicReference it is like using a volatile variable. But as other readers commented, AtomicReference provides additional CAS semantics. So, first decide if you want CAS semantics or not, and if you do only then use AtomicReference.
From the java.util.concurrent.atomic package doc:
The memory effects for accesses and updates of atomics generally follow the rules for volatiles:
get
has the memory effects of reading avolatile
variable.set
has the memory effects of writing (assigning) avolatile
variable.
By the way, the doc for the package is very good and everything is explained...
https://stackoverflow.com/questions/9328252/why-can-an-object-member-variable-not-be-both-final-and-volatile-in-javavolatile
only has relevance to modifications of the variable itself, not the object it refers to. It makes no sense to have a final volatile
field because final fields cannot be modified. Just declare the field final
and it should be fine.https://javax0.wordpress.com/2016/09/21/final-volatile/
Years ago when I last time demonstrated the multi-thread capability Java was still 32-bit, or at least there was 32-bit Java available. On 32 bits you could concurrently increment long variables and because the lower and upper 32 bits were handled in different processor shift there was a chance that two threads garbled some way the non-volatile variable. Now with Java 9 this is not the case. Now Java is 64-bit and I had to demonstrate the need for a volatile on 64-bit before anyone comes up the stupid idea that it was only needed for 32-bit
public
class
VolatileDemonstration
implements
Runnable {
private
Object o =
null
;
private
static
final
Object NON_NULL =
new
Object();
@Override
public
void
run() {
while
( o ==
null
);
System.out.println(
"o is not null"
);
}
public
static
void
main(String[] args)
throws
InterruptedException {
VolatileDemonstration me =
new
VolatileDemonstration();
new
Thread(me).start();
Thread.sleep(
1000
);
me.o = NON_NULL;
}
}
This code will never finish, unless you convert the field o volatile. We also need the 1000ms sleep to allow the JIT to optimize the code of the method run() after which it never reads the variable o ever again. The JIT assumes intra-thread semantics and takes the liberty to optimize the code that way. (Java Language Specification 17.4.7)
A final field can not be volatile. Of course: a final can not change, there is no point to re-read it from the main memory and waste CPU cycles for the synchronization of any change of it between the CPU caches. But that is not true.
Final variables can be changed once.
This is something that novice Java developers tend to forget. When an object is created any final field has the zero value. In case of an object this value is null. The field has to get its final value until the end of the initialization process, that is until the end of the execution of the constructor (any constructor).
- Final fields can be changed once. It is not true that they are not changing never (sic).
- A thread may read the value of a final field once and it may not read it ever again. If the JVM runs for years the thread may keep the value in the thread context in some registry or CPU cache for years as long as it likes.
- Never let this escape from the constructor.
- Among other more trivial things the “never let this escape from the constructor” also means not to pass it as argument to a method that can be overridden or not under the control of the programmer, who is responsible for the current class.
- Write well behaving code or else you will suffer the slings and arrows of your outrageous program.
To answer your question: Yes, I use a
http://www.open-open.com/lib/view/open1516861389789.htmlvolatile
variable to control whether some code continues a loop. The loop tests the volatile
value and continues if it is true
. The condition can be set to false
by calling a "stop" method. The loop sees false
and terminates when it tests the value after the stop method completes execution.
编译器在不改变单线程语义的前提下,为了提高程序的运行速度,可以对字节码指令进行重新排序,所以代码中a、b的赋值顺序,被编译之后可能就变成了先设置b,再设置a。
volatile is Not Always Enough
Even if the
volatile
keyword guarantees that all reads of a volatile
variable are read directly from main memory, and all writes to a volatile
variable are written directly to main memory, there are still situations where it is not enough to declare a variable volatile
.
In the situation explained earlier where only Thread 1 writes to the shared
counter
variable, declaring the counter
variable volatile
is enough to make sure that Thread 2 always sees the latest written value.
In fact, multiple threads could even be writing to a shared
volatile
variable, and still have the correct value stored in main memory, if the new value written to the variable does not depend on its previous value. In other words, if a thread writing a value to the shared volatile
variable does not first need to read its value to figure out its next value.
As soon as a thread needs to first read the value of a
volatile
variable, and based on that value generate a new value for the shared volatile
variable, a volatile
variable is no longer enough to guarantee correct visibility. The short time gap in between the reading of the volatile
variable and the writing of its new value, creates an race condition where multiple threads might read the same value of the volatile
variable, generate a new value for the variable, and when writing the value back to main memory - overwrite each other's values.https://wiki.sei.cmu.edu/confluence/display/java/CON50-J.+Do+not+assume+that+declaring+a+reference+volatile+guarantees+safe+publication+of+the+members+of+the+referenced+object
This safe publication guarantee applies only to primitive fields and object references. Programmers commonly use imprecise terminology and speak about "member objects." For the purposes of this visibility guarantee, the actual member is the object reference; the objects referred to (aka referents) by volatile object references are beyond the scope of the safe publication guarantee. Consequently, declaring an object reference to be volatile is insufficient to guarantee that changes to the members of the referent are published to other threads. A thread may fail to observe a recent write from another thread to a member field of such an object referent.
Furthermore, when the referent is mutable and lacks thread safety, other threads might see a partially constructed object or an object in a (temporarily) inconsistent state [Goetz 2007]. However, when the referent is immutable, declaring the reference volatile suffices to guarantee safe publication of the members of the referent. Programmers cannot use the
volatile
keyword to guarantee safe publication of mutable objects. Use of the volatile
keyword can only guarantee safe publication of primitive fields, object references, or fields of immutable object referents.
Values assigned to an array element by one thread—for example, by calling
setFirst()
—might not be visible to another thread calling getFirst()
because the volatile
keyword guarantees safe publication only for the array reference; it makes no guarantee regarding the actual data contained within the array.
This problem arises when the thread that calls
setFirst()
and the thread that calls getFirst()
lack a happens-before relationship. A happens-before relationship exists between a thread that writes to a volatile variable and a thread that subsequently reads it. However, setFirst()
and getFirst()
read only from a volatile variable—the volatile reference to the array. Neither method writes to the volatile variable.
To ensure that the writes to array elements are atomic and that the resulting values are visible to other threads, this compliant solution uses the
AtomicIntegerArray
class defined in java.util.concurrent.atomic
.AtomicIntegerArray
guarantees a happens-before relationship between a thread that calls atomicArray.set()
and a thread that subsequently calls atomicArray.get()
.
https://www.javamex.com/tutorials/volatile_arrays.shtml
http://javarevisited.blogspot.com/2017/01/can-we-make-array-volatile-in-java.html
declaring an array volatile does not give volatile access to its fields!. At least, it doesn't when elements of the array are accessed with "normal" Java syntax. In other words:
- it is unsafe to call arr[x] = y on an array (even if declared volatile) in one thread and then expect arr[x] to return y from another thread;
- on the other hand, it is safe to call arr = new int[] (or whatever) and expect another thread to then read the new array as that referenced by arr: this is what is meant by declaring the array reference volatile.
The AtomicIntegerArray class implements an int array whose individual fields can be accessed with volatile semantics, via the class's get() and set() methods. Calling arr.set(x, y) from one thread will then guarantee that another thread calling arr.get(x) will read the value y (until another value is read to position x).
Solution 2: re-write the array reference after each field write
This is slightly kludgy and slightly inefficient (since what would be one write now involves two writes) but I believe it is theoretically correct. After setting an element of the array, we re-set the array reference to be itself:
volatile int[] arr = new int[...];
...
arr[4] = 100;
arr = arr;
The marginal benefit of this technique could be:
- it may allow you to fix some broken code with minimal changes if you have code already (incorrectly) using a volatile array and expecting thread-safe element access;
- it saves us creating the wrapper object around the array (which is what happens with IntegerArray and LongArray);
- it's more or less the only option for array types with no available atomic wrapper (e.g. a float array).
http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html
http://javarevisited.blogspot.com/2017/01/can-we-make-array-volatile-in-java.html
The volatile modifier also provides ordering guarantee because the compiler cannot re-order any code or operation which involves volatile variables (primitive and objects), but what is perhaps more important to know and remember is that volatile variable doesn't provide atomicity (except for write to the volatile double variable) and mutual exclusion, which is also the main difference between volatile and synchronizedkeyword.
There are certain restrictions with volatile keyword e.g. you cannot make a member variable both final and volatile at the same time, but you can make a static variable volatile in Java.
There are certain restrictions with volatile keyword e.g. you cannot make a member variable both final and volatile at the same time, but you can make a static variable volatile in Java.
Any modification done on actual collection object e.g. adding or removing elements from ArrayList will not invoke happens-before guarantee or memory barrier refresh.
The answer is, Yes, you can make an array (both primitive and reference type array e.g. an int array and String array) volatile in Java but only changes to reference pointing to an array will be visible to all threads, not the whole array
The answer is, Yes, you can make an array (both primitive and reference type array e.g. an int array and String array) volatile in Java but only changes to reference pointing to an array will be visible to all threads, not the whole array
https://dzone.com/articles/3-tips-for-volatile-fields-in-java
Use Volatile Fields When Writes Do Not Depend on Its Current ValueVolatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread. ... The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the variable become visible to B after reading the volatile variable.
— Java Concurrency in Practice - Brian Goetz, et al.
ublic class WorkerThread extends Thread {
private volatile boolean isRunning = true;
public void run() {
while (isRunning) {
// execute a task
}
}
public void stopWorker() {
isRunning = false;
}
}
java.util.concurrent.CopyOnWriteArrayList's get and set methods are an example of this tip:
public class CopyOnWriteArrayList < E >
implements List < E > , RandomAccess, Cloneable, java.io.Serializable {
private transient volatile Object[] array;
final Object[] getArray() {
return array;
}
final void setArray(Object[] a) {
array = a;
}
private E get(Object[] a, int index) {
return (E) a[index];
}
public E get(int index) {
return get(getArray(), index);
}
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
// Other fields and methods omitted
}
The get method, line 13, simply reads the volatile field array and returns the value at the position index. Writing uses a lock to ensure that only one thread can modify the array at a given time. Line 18 acquires the lock and line 33 releases the lock. Writing requires copying the array when an element is changed, line 24, so that the reading threads do not see an inconsistent state. The writing thread then updates the array, line 25, and sets the new array to the volatile field array, line 26.
Using this tip only writes block writes. Compare this to using synchronized set and get methods, where each operation blocks all other operations. Or java.util.concurrent.locks.ReentrantReadWriteLock, where too many readers can lead to a starvation of writers.
“… the volatile modifier guarantees that any thread that reads a field will see the most recently written value.” - Josh Bloch
"The Java language also provides an alternative, weaker form of synchronization, volatile variables, to ensure that updates to a variable are propagated predictably to other threads.
When a field is declared volatile,the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread." - Java Concurrency In Practice(3.1.4 Volatile Variables)class SharedObj { // Changes made to sharedVar in one thread // may not immediately reflect in other thread static int sharedVar = 6; }
Suppose that two threads are working on SharedObj. If two threads run on different processors each thread may have its own local copy of sharedVar. If one thread modifies its value the change might not reflect in the original one in the main memory instantly. This depends on the write policy of cache. Now the other thread is not aware of the modified value which leads to data inconsistency.
Below diagram shows that if two threads are run on different processors, then value of sharedVar may be different in different threads.
Note that write of normal variables without any synchronization actions, might not be visible to any reading thread (this behavior is called sequential consistency). Although most modern hardware provide good cache coherence therefore most probably the changes in one cache are reflected in other but it’s not a good practice to rely on hardware for to ‘fix’ a faulty application.
class SharedObj { // volatile keyword here makes sure that // the changes made in one thread are // immediately reflect in other thread static volatile int sharedVar = 6; }
- Mutual Exclusion: It means that only one thread or process can execute a block of code (critical section) at a time.
- Visibility: It means that changes made by one thread to shared data are visible to other threads.
Java’s synchronized keyword guarantees both mutual exclusion and visibility. If we make the blocks of threads that modifies the value of shared variable synchronized only one thread can enter the block and changes made by it will be reflected in the main memory. All other thread trying to enter the block at the same time will be blocked and put to sleep.
In some cases we may only desire the visibility and not atomicity. Use of synchronized in such situation is an overkill and may cause scalability problems. Here volatile comes to the rescue. Volatile variables have the visibility features of synchronized but not the atomicity features. The values of volatile variable will never be cached and all writes and reads will be done to and from the main memory. However, use of volatile is limited to very restricted set of cases as most of the times atomicity is desired. For example a simple increment statement such as x = x + 1; or x++ seems to be a single operation but is s really a compound read-modify-write sequence of operations that must execute atomically.
For Java, “volatile” tells the compiler that the value of a variable must never be cached as its value may change outside of the scope of the program itself.
https://dzone.com/articles/java-multi-threading-volatile-variables-happens-be-1
We typically use volatile keyword when we share variables with more than one thread in a multi-threaded environment, and we want to avoid any memory inconsistency errors due to the caching of these variables in the CPU cache.
Consider the following example of producer/consumer, where we are producing/consuming items one at a time .
public class ProducerConsumer {
private String value = "";
private boolean hasValue = false;
public void produce(String value) {
while (hasValue) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Producing " + value + " as the next consumable");
this.value = value;
hasValue = true;
}
public String consume() {
while (!hasValue) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String value = this.value;
hasValue = false;
System.out.println("Consumed " + value);
return value;
}
}
We know that a computer consists of CPUs and Memory Units (and many other parts). Even though the main memory is where all of our program instructions and variables/data reside, during program execution CPUs can store copies of variables in their internal memory (which is known as CPU cache) for performance gain. Since modern computers now have more than one CPUs, there are more than one CPU caches as well.
In a multi-threaded environment, it’s possible for more than one threads to execute at the same time, each one in a different CPU, (although this is totally dependent on the underlying OS), and each one of them may copy variables from main memory into their corresponding CPU cache. When a thread accesses these variables, they will then then access these cached copies, not the actual ones in the main memory.
Now let’s assume that the two threads in our test are running on two different CPUs, and the hasValue flag has been cached on either one of them (or both). Now consider the following execution sequence –
- writerThread produces a value, and changes the hasValue to true. However, this update is only reflected in the cache, not in the main memory.
- readerThread is trying to consume a value, but it’s cached copy of the hasValue flag is set to false. So even though a value has been produced by the writerThread, it cannot consume it as the thread cannot break out of the sleeping loop (hasValue is false).
- Since the readerThread is not consuming the newly generated value, writerThread cannot proceed either as the flag is not being cleared, and hence it will be stuck in its sleeping loop.
- And we have a deadlock in our hands!
This situation will only change if the hasValue flag is synchronized across all caches, which totally depends on the underlying OS.
What’s the solution then? And how does volatile fit into this example?
If we just mark the hasValue flag as volatile, we can be sure that this type of deadlock will not occur –
Marking a variable as volatile will force each thread to read the value of that variable directly from the main memory. Also each write to a volatile variable will be flushed into the main memory immediately. If the threads decide to cache the variable, it will be synced with the main memory on each read/write.
I See. Is This All Volatile Does, Forcing Threads to Read/Write Variables Directly From Memory?
Actually it has some further implications. Accessing a volatile variable establishes a happens-before relationship between program statements.
What is a Happens-before Relationship?
A happens-before relationship between two program statements is sort a guarantee which ensures that any memory writes by one statement are visible to another statement.
How Does It Relate With Volatile?
When we write to a volatile variable, it creates a happens-before relationship with each subsequent read of that same variable. So any memory writes that have been done until that volatile variable write, will subsequently be visible to any statements that follow the read of that volatile variable.
// Definition: Some variables
private int first = 1;
private int second = 2;
private int third = 3;
private volatile boolean hasValue = false;
// First Snippet: A sequence of write operations being executed by Thread 1
first = 5;
second = 6;
third = 7;
hasValue = true;
// Second Snippet: A sequence of read operations being executed by Thread 2
System.out.println("Flag is set to : " + hasValue);
System.out.println("First: " + first); // will print 5
System.out.println("Second: " + second); // will print 6
System.out.println("Third: " + third); // will print 7
Let’s assume that the above two snippets being executed by two different threads – thread 1 and 2. When the first thread changes hasValue, it will not only flush this change to main memory, but it will also cause the previous three writes (and any other previous writes) to be flushed into the main memory as well! As a result, when the second thread accesses these three variables it will see all the writes made by thread 1, even if they were all cached before (and these cached copies will be updated as well)!
This is the exactly why we did not have to mark the value variable in our first example with volatile as well. Since we wrote to that variable before accessing hasValue, and read from it after reading hasValue, it was automatically synced with the main memory.
This has another interesting consequence. JVM is famous for its program optimization. Sometimes it reorders the program statements to boost performance without changing the output of the program. As an example, it can change the following sequence of statements –
Into this –
However, when the statements involve accessing a volatile variable, then it will never move a statement occurring before a volatile write after it. Which means, it will never transform this –
into this –
Even though from the perspective of program correctness both of them seem to be equivalent. Note that the JVM is still allowed to reorder the first three writes among them as long as they all appear before the volatile write.
Similarly, the JVM will also not change the order of a statement which appears after a volatile variable read to appear before the access. Which means the following –
Will never be transformed by the JVM into this –
However, the JVM can certainly reorder the last three reads among them, as long as they keep appearing after the volatile read.
I Sense a Performance Penalty Has to Be Paid For Volatile Variables.
You got that right, since volatile variables force main memory access, and accessing main memory is always way slower than accessing CPU caches. It also prevents certain program optimizations by JVM as well, further reducing the performance.
Can We Always Use Volatile Variables to Maintain Data Consistency Across Threads?
Unfortunately not. When more than one threads read and write to the same variable, then marking it as volatile is not enough to maintain consistency. Consider the following UnsafeCounter class –
public class UnsafeCounter {
private volatile int counter;
public void inc() {
counter++;
}
public void dec() {
counter--;
}
public int get() {
return counter;
}
}
The code is pretty self-explanatory. We are incrementing the counter in one thread, and decrementing it in another by same number of times. After running this test we expect the counter to hold 0, but this is not guaranteed. Most of the times it will be 0, and some of the times it will be -1, -2, 1, 2 i.e., any integer value between the range [-5, 5].
Why does this happen? It happens because both the increment and the decrement operation of the counter are not atomic – they do not happen all at once. Both of them consists of multiple steps, and the sequence of steps overlap with each other.
Yup. Using the synchronized keyword also establishes a happens-before relationship between statements. Entering a synchronized method/block establishes a happens-before relationship between the statements that appear before it and the ones inside the method/block. For a full list of what establishes a happens-before relationship, please go here.
What is volatile variable in Java - When to use | Java67volatile variable in Java is a special variable which is used to signal threads, compiler that this particular variables values is going to be updated by multiple thread inside Java application. By making a variable volatile using volatile keyword in Java, application programmer ensures that its value should always been read from main memory and thread should not used cached value of that variable from there own stack.
From JDK5 on, volatile variable also guarantees "happens-before" relationship, which means not only other thread has visibility of latest value of volatile variable but also all the variable seen by the thread which has updated value of volatile variable before this threads sees it.
When to use Volatile variable in Java
1) Any variable which is shared between multiple threads should be made variable, in order to ensure that all thread must see latest value of volatile variable.
2) A signal to compiler and JIT to ensure that compiler does not change ordering or volatile variable and moves them out of synchronized context.
3) You want to save cost of synchronization as volatile variables are less expensive than synchronization.
http://www.javacodegeeks.com/2014/07/making-operations-on-volatile-fields-atomic.html
Why not use volatile all the time?
Volatile read and write access is substantially slower. When you write to a volatile field it stalls the entire CPU pipeline to ensure the data has been written to cache. Without this, there is a risk the next read of the value sees an old value, even in the same thread (See AtomicLong.lazySet() which avoids stalling the pipeline)
The penalty can be in the order of 10x slower which you don’t want to be doing on every access.
What are the limitations of volatile?
A significant limitation is that operations on the field is not atomic, even when you might think it is.
http://codepub.cn/2015/04/10/Java's-volatile-boolean-AutomaticBoolean-analysis/
volatile关键字是一个类型修饰符,被设计用来修饰被不同线程访问和修改的变量,在JVM1.2之前,Java的内存模型实现总是从主存读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的使用变得非常重要。
在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
要解决这个问题,需要把变量声明为volatile(不稳定的),以后用到该变量都会到主存中进行存取,一般多任务环境下各任务间共享的标志都应该加volatile修饰。volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值,而且当成员变量发生变化时,强迫线程将变化值回写到共享内存。
Java语言中的volatile变量可以被看作是一种“程度较轻的synchronized”;与synchronized块相比,volatile变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是synchronized的一部分。Volatile变量具有synchronized的可见性特性,但是不具备原子特性。volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性。
注意:不要将volatile用在getAndOperate场合,仅仅set或者get的场景是适合volatile的。
由以上测试用例可以看出,volatile boolean是无法保证线程安全的,在一个线程占用flag变量的时候,
其他线程也可以占用flag变量,所以多个线程均可以打印出消息。
其他线程也可以占用flag变量,所以多个线程均可以打印出消息。
java.util.concurrent.atomic是在JDK1.5之后引入的包,在JDK中的说明如下
A small toolkit of classes that support lock-free thread-safe programming on single variables. In essence, the classes in this package extend the notion of volatile values, fields, and array elements to those that also provide an atomic conditional update operation of the form:
1
| boolean compareAndSet(expectedValue, updateValue);
|
This method (which varies in argument types across different classes) atomically sets a variable to the updateValue if it currently holds the expectedValue, reporting true on success. The classes in this package also contain methods to get and unconditionally set values, as well as a weaker conditional atomic update operation weakCompareAndSet described below.
该包提供了一组原子类,在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择另一个线程进入。
public static volatile AtomicBoolean flag = new AtomicBoolean(true); public static void main(String[] args) { for (int j = 0; j < 20; j++) { Thread t = new Thread(new Test()); t.start(); } } public void run() { if (flag.compareAndSet(true, false)) { System.out.println("我成功了!"); } }
Atomic类不仅仅提供了对数据操作的线程安全保证,而且提供了一系列的语义清晰的方法,如incrementAndGet() 、getAndIncrement() 等,使用方便,Atomic的内部实现使用的是更加高效的CAS(compareand swap)+volatile,从而避免了synchronized的高开销,执行效率大幅提升,出于性能考虑强烈建议使用Atomic,而不是synchronized关键字。
http://www.importnew.com/11157.html重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境。
编译期重排序
编译期重排序的典型就是通过调整指令顺序,在不改变程序语义的前提下,尽可能减少寄存器的读取、存储次数,充分复用寄存器的存储值。
假设第一条指令计算一个值赋给变量A并存放在寄存器中,第二条指令与A无关但需要占用寄存器(假设它将占用A所在的那个寄存器),第三条指令使用A的值且与第二条指令无关。那么如果按照顺序一致性模型,A在第一条指令执行过后被放入寄存器,在第二条指令执行时A不再存在,第三条指令执行时A重新被读入寄存器,而这个过程中,A的值没有发生变化。通常编译器都会交换第二和第三条指令的位置,这样第一条指令结束时A存在于寄存器中,接下来可以直接从寄存器中读取A的值,降低了重复读取的开销。
Java存储模型中的重排序
在Java存储模型(Java Memory Model, JMM)中,重排序是十分重要的一节,特别是在并发编程中。JMM通过happens-before法则保证顺序执行语义,如果想要让执行操作B的线程观察到执行操作A的线程的结果,那么A和B就必须满足happens-before原则,否则,JVM可以对它们进行任意排序以提高程序性能。
volatile关键字可以保证变量的可见性,因为对volatile的操作都在Main Memory中,而Main Memory是被所有线程所共享的,这里的代价就是牺牲了性能,无法利用寄存器或Cache,因为它们都不是全局的,无法保证可见性,可能产生脏读。
volatile还有一个作用就是局部阻止重排序的发生,对volatile变量的操作指令都不会被重排序,因为如果重排序,又可能产生可见性问题。
在保证可见性方面,锁(包括显式锁、对象锁)以及对原子变量的读写都可以确保变量的可见性。但是实现方式略有不同,例如同步锁保证得到锁时从内存里重新读入数据刷新缓存,释放锁时将数据写回内存以保数据可见,而volatile变量干脆都是读写内存。
http://www.blogjava.net/aoxj/archive/2012/06/16/380926.html
++操作,无论是i++还是++i,都不是原子操作!
而一个非原子操作,在多线程并发下会有线程安全的问题:这里稍微解释一下,上面的"++"操作符,从原理上讲它其实包含以下:计算加1之后的新值,然后将这个新值赋值给原变量,返回原值。类似于下面的代码
private int counter = 0;
public int getCount ( ) {
int result = counter;
int newValue = counter + 1; // 1. 计算新值
counter = newValue; // 2. 将新值赋值给原变量
return result;
}
public int getCount ( ) {
int result = counter;
int newValue = counter + 1; // 1. 计算新值
counter = newValue; // 2. 将新值赋值给原变量
return result;
}
多线程并发时,如果两个线程同时调用getCount()方法,则他们可能得到相同的counter值。为了保证安全,一个最简单的方法就是在getCount()方法上做同步:
private int counter = 0;
public synchronized int getCount ( ) {
return counter++;
}
public synchronized int getCount ( ) {
return counter++;
}
这样就可以避免因++操作符的非原子性而造成的并发危险。
我们在这个案例基础上稍微再扩展一下,如果这里的操作是原子操作,就可以不用同步而安全的并发访问吗?我们将这个代码稍作修改:
private int something = 0;
public int getSomething ( ) {
return something;
}
public void setSomething (int something) {
this.something = something;
}
public int getSomething ( ) {
return something;
}
public void setSomething (int something) {
this.something = something;
}
假设有多线程同时并发访问getSomething()和setSomething()方法,那么当一个线程通过调用setSomething()方法设置一个新的值时,其他调用getSomething()的方法是不是立即可以读到这个新值呢?这里的"this.something = something;" 是一个对int 类型的赋值,按照java 语言规范,对int的赋值是原子操作,这里不存在上面案例中的非原子操作的隐患。
但是这里还是有一个重要问题,称为"内存可见性"。这里涉及到java内存模型的一系列知识,限于篇幅,不详尽讲述,不清楚这些知识点的可以自己翻翻资料,最简单的办法就是google一下这两个关键词"java 内存模型", "java 内存可见性"。或者,可以参考这个帖子"java线程安全总结", http://www.iteye.com/topic/806990。
解决这里的"内存可见性"问题的方式有两个,一个是继续使用 synchronized 关键字,代码如下
private int something = 0;
public synchronized int getSomething ( ) {
return something;
}
public synchronized void setSomething (int something) {
this.something = something;
}
public synchronized int getSomething ( ) {
return something;
}
public synchronized void setSomething (int something) {
this.something = something;
}
另一个是使用volatile 关键字,
private volatile int something = 0;
public int getSomething ( ) {
return something;
}
public void setSomething (int something) {
this.something = something;
}
public int getSomething ( ) {
return something;
}
public void setSomething (int something) {
this.something = something;
}
使用volatile 关键字的方案,在性能上要好很多,因为volatile是一个轻量级的同步,只能保证多线程的内存可见性,不能保证多线程的执行有序性。因此开销远比synchronized要小。
让我们再回到开始的案例,因为我们采用直接在 getCount() 方法前加synchronized 的修改方式,因此不仅仅避免了非原子性操作带来的多线程的执行有序性问题,也"顺带"解决了内存可见性问题。
OK,现在可以继续了,前面讲到可以通过在 getCount() 方法前加synchronized 的方式来解决问题,但是其实还有更方便的方式,可以使用jdk 5.0之后引入的concurrent包中提供的原子类,java.util.concurrent.atomic.Atomic***,如AtomicInteger,AtomicLong等。
private AtomicInteger counter = new AtomicInteger(0);
public int getCount ( ) {
return counter.incrementAndGet();
}
public int getCount ( ) {
return counter.incrementAndGet();
}
Atomic类不仅仅提供了对数据操作的线程安全保证,而且提供了一系列的语义清晰的方法如incrementAndGet(),getAndIncrement,addAndGet(),getAndAdd(),使用方便。更重要的是,Atomic类不是一个简单的同步封装,其内部实现不是简单的使用synchronized,而是一个更为高效的方式CAS (compare and swap) + volatile,从而避免了synchronized的高开销,执行效率大为提升。限于篇幅,关于“CAS”原理就不在这里讲诉。
因此,出于性能考虑,强烈建议尽量使用Atomic类,而不要去写基于synchronized关键字的代码实现。
最后总结一下,在这个帖子中我们讲诉了一下几个问题:
1. ++操作不是原子操作
2. 非原子操作有线程安全问题
3. 并发下的内存可见性
4. Atomic类通过CAS + volatile可以比synchronized做的更高效,推荐使用
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility
http://javarevisited.blogspot.kr/2015/10/133-java-interview-questions-answers-from-last-5-years.html
Multithreading, Concurrency and Thread basics Questions
1) Can we make array volatile in Java?
Yes, you can make an array volatile in Java but only the reference which is pointing to an array, not the whole array. What I mean, if one thread changes the reference variable to points to another array, that will provide volatile guarantee, but if multiple threads are changing individual array elements they won't be having happens before guarantee provided by volatile modifier.
2) Can volatile make a non-atomic operation to atomic?
One example I have seen is having a long field in your class. If you know that a long field is accessed by more than one thread e.g. a counter, a price filed or anything, you better make it volatile. Why? because reading to a long variable is not atomic in Java and done in two steps, If one thread is writing or updating long value, it's possible for another thread to see half value (fist 32-bit). While reading/writing a volatile long or double (64 bit) is atomic.
3) What are practical uses of volatile modifier?
One of the practical use of volatile variable is to make reading double and long atomic. Both double and long are 64-bit wide and they are read in two parts, first 32-bit first time and next 32-bit second time, which is non-atomic but volatile double and long read is atomic in Java. Another use of volatile variable is to provide a memory barrier, just like it is used inDisrupter framework. Basically, Java Memory model inserts a write barrier after you write to volatile variable and a read barrier before you read it. Which means, if you write to volatile field then its guaranteed that any thread accessing that variable will see the value you wrote and anything you did before doing that write into the thread is guaranteed to have happened and any updated data values will also be visible to all threads, because the memory barrier flushed all other writes to the cache.
4) What guarantee volatile variable provides? (answer)
volatile variables provide the guarantee about ordering and visibility e.g. volatile assignment cannot be re-ordered with other statements but in the absence of any synchronization instruction compiler, JVM or JIT are free to reorder statements for better performance. volatile also provides the happens-before guarantee which ensure changes made in one thread is visible to others. In some cases volatile also provide atomicity e.g. reading 64-bit data types like long and double are not atomic but read of volatile double or long is atomic.
Read full article from What is volatile variable in Java - When to use | Java67