volatile 和 atomic 原子性的区别和联系
作者:wenyinfeng
转载时,请注明原文出处,谢谢!
An incorrect piece of lore that is often repeated in Java threading discussions is, "Atomic operations do not need to be synchronized." An atomic operation is one that cannot be interrupted by the thread scheduler; if the operation begins, then it will run to completion before the possibility of a context switch.
Atomicity applies to "simple operations" on primitive types except for longs and doubles. Reading and writing primitive variables other than long and double is guaranteed to go to and from memory as indivisible (atomic) operations. However, the JVM is allowed to
perform reads and writes of 64- bit quantities (long and double variables) as two separate 32-bit operations, raising the possibility that a context switch could happen in the middle of a
read or write, and then different tasks could see incorrect results (this is sometimes called word tearing, because you might see the value after only part of it has been changed). However, you do get atomicity (for simple assignments and returns) if you use the volatile keyword when defining a long or double variable (note that volatile was not working properly before Java SE5). Different JVMs are free to provide stronger guarantees, but you should not rely on platform-specific features.
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.
原子操作就是不能被线程调度机制中断的操作。不正确的认识:原子操作不需要进行同步。
在Java 中除了 long 和 double 之外的所有基本类型的读和赋值,都是原子性操作。而64位的long 和 double 变量由于会被JVM当作两个分离的32位来进行操作,所以不具有原子性,会产生字撕裂问题。但是当你定义long或double变量时,如果使用 volatile关键字,就会获到(简单的赋值与返回操作的)原子性(注意,在Java SE5之前,volatile一直不能正确的工作)。见第四版《Thinking in java》第21章并发。
volatile关键字确保了应用中的可视性。如果你将一个域声明为volatile,那么只要这个域产生了写操作,那么所有的读操作就都可以看到这个修改。
下面来看看volatile 和原子性的区别和联系。我将从下面几个问题进行思考和探索。
第1个问题:如何证明 作者上面所说的long 和 double 的简单操作是非原子性的 - 会产生字撕裂问题,而使用volatile 关键字可以保证 long 或 double 的简单操作具有原子性,以及验证其它的基本类型(如int)的简单操作具有原子性。
我的思路:
具体见下面我写的测试代码
// 证明 long 变量简单操作(赋值和返回)不具有原子性,存在字撕裂问题。验证 volatile 可确保
// long 变量简单操作具有原子性。验证 int 变量简单操作(赋值和返回)具有原子性
package concurrency;
import java.util.concurrent.*;
class Operation{
}
public class AtomicTest{