1. 程式人生 > >Java關鍵字volatile,原子性,變數可見性

Java關鍵字volatile,原子性,變數可見性

The volatile keyword also ensures visibility across the application. If you declare a field to be volatile, this means that as soon as a write occurs for that field, all reads will see the change. This is true even if local caches are involved—volatile fields are immediately written through to main memory, and reads occur from main memory.

大意:可見性和原子性是不同的兩個概念。對一個非volatile變數的原子操作的結果不會立即重新整理到主從。多執行緒環境下對某個共享變數訪問時,要麼把這個變數定義成volatile的,要麼使用synchronization,這樣就保證了該變數的可見性。但如果該變數的操作是在synchronized方法或程式碼塊中的話,就不用將該變數定義為volatile了,因為synchronization同步機制會強迫重新整理到記憶體,強迫一個執行緒對共享變數做的改變對整個應用可見。
It’s important to understand that atomicity and volatility are distinct concepts. An atomic operation on a non-volatile field will not necessarily be flushed to main memory, and so another task that reads that field will not necessarily see the new value. If multiple tasks are accessing a field, that field should be volatile; otherwise, the field should only be accessed via synchronization. Synchronization also causes flushing to main memory, so if a field is completely guarded by synchronized methods or blocks, it is not necessary to make it volatile. 


volatile關鍵字的侷限:
volatile doesn’t work when the value of a field depends on its previous value (such as incrementing a counter), nor does it work onfields whose values are constrained by the values of other fields, such as the lower and upper bound of a Range class which must obey the constraint lower <= upper. 
It’s typically only safe to use volatile instead of synchronized if the class has only one mutable field. Again, your first choice should be to use the synchronized keyword—that’s the safest approach, and trying to do anything else is risky.


If you define a variable as volatile, it tells the compiler not to do any optimizations that would remove reads and writes that keep the field in exact synchronization with the local data in the threads. In effect, reads and writes go directly to memory, and are not cached, volatile also restricts compiler reordering of accesses during optimization. However, volatile doesn’t affect the fact that an increment isn’t an atomic operation.


Basically, you should make a field volatile if that field could be simultaneously accessed by multiple tasks, and at least one of those accesses is a write. For example, a field that is used as a flag to stop a task must be declared volatile.