volatile基础

2018-08-05

volatile基础

[TOC]

1.概念

A.轻量级同步机制,与synchronized重量级锁不同,不会引起线程的上下文切换,但是需要注意两个问题:

  1. 复合类操作无法同步 如 count++
  2. 在其他变量的不变式中包含则无法同步 如常量和条件(后续再深入理解不变式)

B.阻止指令重排

2.内存可见性

volatile是轻量级的同步机制,相比于synchronized重量级锁来说 ,能够节省更大的消耗,虽然在总体能力上不如synchronized安全,但是在一定场合也具有自己的优势,合理的利用volatile能够让程序更高效的运行

volatile修饰的属性对整个内存来说是可见的,即:每个线程获取到的该数据都是最新的(此处内存分配属逻辑模拟)

  • A线程(工作内存)→
    } 主内存空间 
    
  • B线程(工作内存)→

对线程来说,正常的共享资源会从主内存中copy到自己的工作内存中,这里如同内存和硬盘的区别,可以更加快速的使用copy的资源,但是此时的工作内存对于其他线程是不可见的,因此很容易因为并发产生数据异常

当使用volatile时,该共享资源每次更新都会被同步到主内存空间中,对于其他线程来说,该数据始终是最新的,因此可以一定程度的解决并发的问题,但是有一些情况volatile无法直接实现,如非复合类操作

3.解决count++原子性问题

count++之类的非符合类操作,volatile无法保证他的原子性问题,使共享资源无法实时同步,进而引发并发问题

复合类操作过程:

  1. 读取
  2. 运算
  3. 赋值

因为volatile本身只是轻量级的同步机制,并非锁机制,当复合类操作的过程中可能有其他线程继续操作该资源,从而导致并发问题

解决:循环CAS 方案(待研究)

4.阻止指令重排

指令重排是java优化程序性能的一种手段(提供并行度),但是重排也有一定的规则:

指令重排不会对存在依赖关系的数据进行操作

​ 如a=1;b=a

指令重排不会对单线程下的结果进行操作

​ 如a=1;b=2;c=a+b;

被volatile修饰的变量,在编译时,会插入内存屏障来阻止处理器等对数据的指令重排,阻止指令重排规则:

  1. 第一个是volatile读操作时,无论第二个是什么操作,都会阻止指令重排
  2. 第二个是volatile写操作时,无论第一个是什么操作,都会阻止指令重排
  3. 第一个是volatile写操作,得个是volatile读操作时,都会阻止指令重排