Volatile相关知识点

时间:2020-8-26 作者:admin


文章目录

volatile内存定义

当写一个volatile变量时,JMM会将该线程写入到工作内存的值同步刷新到主内存中。
当读一个volatile变量时,JMM会将该线程工作内存中的值置为无效,直接从主内存中读取值并刷新到工作内存中。

特点

  • 只能用来修饰变量
  • 可以保证变量的可见性 ,也就是当这个变量修改后,所有线程都会被要求重新从主内存中再次拷贝一次该变量的值到工作空间中。主要是通过两个操作来保证共享变量的可见性:
    1、被volatile关键词修饰的变量,当CPU处理完该数据将数据刷回高速缓存区时,会立马将数据刷回内存。
    2、当被volatile关键词修饰的变量刷回内存时,立马让其他CPU中使用的该变量无效,在最开始时是采用在总线上添加LOCK#锁来做的,但该方式效率比较低,后续Intel将实现方式改为只要CPU在修改了被volatile修饰的共享变量后,就会向其他CPU发出信号,将读取到工作内存中的变量无效化,而其他CPU在需要使用这个变量时,如果检测到这个无效信号,就会重新从主内存中再次读取一次该变量的值,从而保证了可见性。
  • 同时该关键词还可以禁止指令重排,实现原理一个是在字节码层面添加了ACC_VOLATILE关键词保证,另一个是在JVM中通过插入内存屏障来保证,内存屏障就是保证前者执行完之后才执行后者,有点类似依赖关系,有LOADLOAD、LOADSTORE、STORELOAD、STORESTORE四种情况。
    LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2, 在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。 
    
    StoreStore屏障:对于这样的语句Store1; StoreStore; Store2, 在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。 
    
     LoadStore屏障:对于这样的语句Load1; LoadStore; Store2, 在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
    
    StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2, 在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。
    
  • volatile无法保证原子性,是因为可能存在同时多个线程都要将工作内存的值写入主内存,这时候即使CPU接收到了变量无效的信号,也无法停止写入的动作,因此volatile只能在CPU读取值的时候重新刷新变量的真实值,写入不受限制。

使用场景

  • 使用了volatile的地方有很多,典型的是Atomic*系列里面的value都使用了这个关键词来修饰,目的就是为了保证在不同线程中该变量的可见性。
  • volatile适合用在一个线程写,多个线程读的场景,可以理解是synchronize的轻量级锁。
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。