Java:修饰符volatile

Java内存模型中,有主内存和每个线程各自的工作内存,虚拟机和硬件可能会让线程工作内存优先存储于寄存器和高速缓存中,以提高性能。

所有变量都存储在主内存中,线程工作内存中保存了此线程使用到的变量的副本。工作内存在线程之间是隔离的,对其他线程不可见。线程对变量的所有操作都必须在工作内存中进行,修改后的变量副本要写回主内存。这样就会出现同一个变量在某个瞬间,在一个线程的工作内存中的值可能与另外一个线程工作内存中的值,或者主内存中的值不一致的情况。

Volatile 变量

Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此,单独使用 volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式(Invariants)的类(例如 “start <=end”)。

出于简易性或可伸缩性的考虑,您可能倾向于使用 volatile 变量而不是锁。当使用 volatile 变量而非锁时,某些习惯用法(idiom)更加易于编码和阅读。此外,volatile 变量不会像锁那样造成线程阻塞,因此也很少造成可伸缩性问题。在某些情况下,如果读操作远远大于写操作,volatile 变量还可以提供优于锁的性能优势。

一个变量声明为volatile,就意味着这个变量被修改时其他所有使用到此变量的线程都立即能见到变化(称之为可见性)。具体是在每次使用前都要先刷新,以保证别的线程中的修改已经反映到本线程工作内存中,因此可以保证执行时的一致性。以下例子展现了volatile的作用:

public class StoppableTask extends Thread {  
  private volatile boolean pleaseStop;  
  
  public void run() {  
    while (!pleaseStop) {  
      // do some stuff...  
    }  
  }  
  
  public void tellMeToStop() {  
    pleaseStop = true;  
  }  
}

假如pleaseStop没有被声明为volatile,线程执行run的时候检查的是自己的副本,就不能及时得知其他线程已经调用tellMeToStop()修改了pleaseStop的值。

Volatile一般情况下并不能代替sychronized,因为volatile不能保证操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,依然可能由于不同线程交替执行而出现写入脏数据的情况。也就是说,如果对变量值的修改需要依赖于变量之前的值,那么volatile不能保证一致性,需要用sychronized,或者使用atomic类型(java.util.concurrent.atomic.*);而上面的代码例子是可以使用volatile的典型场景。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,494评论 11 349
  • 文/某企鹅 今天对于许多养狗、爱狗的人来说,应该是个不太开心的日子吧,然而我并不能实质性地去做些什么来改变这个现状...
    5fed66fbb1fd阅读 3,644评论 4 6
  • 夏日清晨,第一束阳光还未射入闺阁,女孩子已经起身,静静地坐到了漆黑的窗前,一丝丝阳光射入屋中,黑暗被一点点驱逐。女...
    乐嘉阅读 4,798评论 0 3
  • 有时走在车水马龙马路上,经常会想到一个问题,我是谁,我为什么会在这里,我要到哪里去。相信这是很多人都有的迷茫人们...
    黑白电视阅读 3,382评论 0 0
  • 从小到大,总能听到这么一句话:是金子总是会发光的。然而想要发光,前提是我们必须得是块金子,所以我们需要不断的默默地...
    一只两只iing阅读 5,231评论 0 1

友情链接更多精彩内容