volatile关键字

volatile
volatile 关键字的作用
对于可见性,Java 提供了 volatile 关键字来保证可见性和禁止指令重排。
volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是
可见的。当一个共享变量被 volatile 修饰时,它会保证修改的值会立即被更新
到主存,当有其他线程需要读取时,它会去内存中读取新值。
从实践角度而言,volatile 的一个重要作用就是和 CAS 结合,保证了原子性,
详细的可以参见 java.util.concurrent.atomic 包下的类,比如
AtomicInteger。
volatile 常用于多线程环境下的单次操作(单次读或者单次写)。
Java 中能创建 volatile 数组吗?
能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而
不是整个数组。意思是,如果改变引用指向的数组,将会受到 volatile 的保
护,但是如果多个线程同时改变数组的元素,volatile 标示符就不能起到之前
的保护作用了。
volatile 变量和 atomic 变量有什么不同?
volatile 变量可以确保先行关系,即写操作会发生在后续的读操作之前, 但它
并不能保证原子性。例如用 volatile 修饰 count 变量,那么 count++ 操作就
不是原子性的。
而 AtomicInteger 类提供的 atomic 方法可以让这种操作具有原子性如
getAndIncrement()方法会原子性的进行增量操作把当前值加一,其它数据类型
和引用变量也可以进行相似操作。
volatile 能使得一个非原子操作变成原子操作吗?
关键字 volatile 的主要作用是使变量在多个线程间可见,但无法保证原子性,
对于多个线程访问同一个实例变量需要加锁进行同步。
虽然 volatile 只能保证可见性不能保证原子性,但用 volatile 修饰 long 和
double 可以保证其操作原子性。
所以从 Oracle Java Spec 里面可以看到:
• 对于 64 位的 long 和 double,如果没有被 volatile 修饰,那么对其操作
可以不是原子的。在操作的时候,可以分成两步,每次对 32 位操作。
• 如果使用 volatile 修饰 long 和 double,那么其读写都是原子操作
• 对于 64 位的引用地址的读写,都是原子操作
• 在实现 JVM 时,可以自由选择是否把读写 long 和 double 作为原子操作
• 推荐 JVM 实现为原子操作

你可能感兴趣的:(java)