Java并发之同步 —— volatile关键字及原子性、可见性

前言

在理解volatile前,先理解原子性和可见性

原子性:

操作的不可分割性。如++count 实际上是可以分割的三个独立操作,读取->修改->写入,其结果依赖之前的状态,所以并非原子性

可见性:

一个线程修改了对象状态后, 其他线程能够看到发生的状态变化

 "可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。在单线程环境中,如果向某个变量先写入值,然后在没有其他写入操作的情况下读取这个变量,那么总能得 到相同的值。这看起来很自然。然而,当读操作和写操作在不同的线程中执行时,情况却并非 如此,这听起来或许有些难以接受。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见 性,必须使用同步机制。"  

Volatile理解

volatile 关键字为实例域的同步访问提供了一种免锁机制。如果声明一个域为 volatile , 那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。 例如, 假定一个对象有一个布尔标记 done , 它的值被一个线程设置却被另一个线程査 询,如同我们讨论过的那样,你可以使用锁:

private boolean done;
public synchronized boolean isDoneO { return done; }
public synchronized void setDoneO { done = true; }

局限性

volatile 变量不能提供原子性。例如方法,

public void flipDone() { done = !done; } // not atomic 

不能确保翻转域中的值。不能保证读取、 翻转和写入不被中断。

使用条件

当且仅当满足以下所有条件时,才应该使甩volatile变量: 

  • 对变量的写人操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
  • 该变量不会与其他状态变量一起纳人不变性条件中。
  • 在访问变量时不需要加锁。

小结 

加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能保证可见性。

参考:Java并发编程实战

          Java核心技术 卷I (第十版)

猜你喜欢

转载自blog.csdn.net/zl_momomo/article/details/81355925