多线程学习(5)volatile 和 synchronized 的区别

知足同步三个基本条件:

1.原子性缓存

原子性是指操做是不可分的。其表如今于对于共享变量的某些操做,应该是不可分的,必须连续完成。例如a++,对于共享变量a的操做,实际上会执行三个步骤,1.读取变量a的值  2.a的值+1  3.将值赋予变量a 。 这三个操做中任何一个操做过程当中,a的值被人篡改,那么都会出现咱们不但愿出现的结果。因此咱们必须保证这是原子性的。多线程

2.可见性:一个线程对共享变量值得修改,可以及时的被其余线程看到 并发

多线程高并发中,线程之间的通讯是靠内存共享,即一个对象或变量,它在堆中的主内存中,每个请求能够看作一个线程,每个线程,都想操做这个主内存的对象或变量,线程会复制一份主内存中的对象或变量,到本身的线程本地栈内存中,直到操做完毕,才会将本地栈内存的对象或变量,赋值给主内存。若是不加同步锁,主内存中的对象或变量,值就容易被最后提交操做的线程覆盖,发生错误。高并发

3.有序性:性能

指令重排序:代码书写的顺序与实际执行的顺序不一样,指令重排序是编译器或处理器为了提升程序性能而作的优化。优化

1.编译器优化的重排序(编译器优化)spa

2.指令级并行重排序(处理器优化)线程

3.内存系统的重排序(处理器优化)对象

是否是全部的语句的执行顺序均可以重排呢?

答案是否认的。为了讲清楚这个问题,先讲解另外一个概念:数据依赖性blog

什么是数据依赖性?

若是两个操做访问同一个变量,且这两个操做中有一个为写操做,此时这两个操做之间就存在数据依赖。数据依赖分下列三种类型:

名称 代码示例 说明
写后读 a = 1;b = a; 写一个变量以后,再读这个位置。
写后写 a = 1;a = 2; 写一个变量以后,再写这个变量。
读后写 a = b;b = 1; 读一个变量以后,再写这个变量。

上面三种状况,只要重排序两个操做的执行顺序,程序的执行结果将会被改变。因此,编译器和处理器在重排序时,会遵照数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操做的执行顺序。也就是说:在单线程环境下,指令执行的最终效果应当与其在顺序执行下的效果一致,不然这种优化便会失去意义。这句话有个专业术语叫作as-if-serial semantics (as-if-serial语义)

int num1=1;//第一行
int num2=2;//第二行
int sum=num1+num;//第三行

单线程:第一行和第二行能够重排序,但第三行不行

重排序不会给单线程带来内存可见性问题

多线程中程序交错执行时,重排序可能会照成内存可见性问题。

 

synchronized关键字

synchronized经过操做对象锁和类对象锁,修饰方法和代码块,则保证持有锁的线程操做完毕,从新赋值主内存中的对象或变量后,其余线程再去争抢锁,继续操做主内存对象。达到一个线程的执行结果对其余线程的。知足上面的三个原则。

 

volatile变量每次被线程访问时,都强迫从主内存中读取该变量的值,而当变量发生变化的时候都会强迫线程将最新的值刷新到主内存中。

这样不一样的变量总能看到最新的值。

能够把volatile变量的单个读写,当作是使用同一个锁对这些单个读/写操做作了同步。

volatile关键字:

  • 可以保证volatile变量的可见性
  • 只能保证单个volatile变量的原子性,对于volatile++这种复合操做不具备原子性
  • 对volatile变量执行写操做时,会在写操做后加入一条store屏障指令

    • store指令会在写操做后把最新的值强制刷新到主内存中。同时还会禁止cpu对代码进行重排序优化。这样就保证了值在主内存中是最新的。
  • 对volatile变量执行读操做时,会在读操做前加入一条load屏障指令

    • load指令会在读操做前把内存缓存中的值清空后,再从主内存中读取最新的值。

 

 

synchronized和volatile的比较:

  • synchronized锁住的是变量和变量的操做,而volatile锁住的只是变量,并且该变量的值不能依赖它自己的值,volatile算是一种轻量级的同步锁
  • volatile不须要加锁,比synchronized更加轻量级,不会阻塞线程。
  • 从内存可见性角度讲,volatile读至关于加锁,volatilexie至关于解锁。
  • synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,没法保证原子性。

注:因为voaltile比synchronized更加轻量级,因此执行的效率确定是比synchroized更高。在能够保证原子性操做时,能够尽可能的选择使用volatile。在其余不能保证其操做的原子性时,再去考虑使用synchronized。

相关文章
相关标签/搜索