synchronized与volatile

在这之前我们应该先了解一下Java内存模型

请戳~~~~>Java内存模型

Volatile关键字

保证操作变量的可见性和有序性,不保证操作变量的原子性

这段代码本应该是20000,但是为什么比20000小呢??

因为num++这个指令它并不具有原子性,它是分为几步执行的,volatile能够保证拿到的时候是正确的数据,但是由于它只走了一步,别的线程把这个变量的值改了,它并不知道还是用的之前的数据,所以导致最后的结果比20000小

但是如果用synchronized就会保证原子性

可见性:

A),在汇编层会对volatile修饰的关键字加Lock前缀

Lock前缀指令实际上是一个内存屏障,内存屏障会提供三个功能

  1. 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
  2. 它会强制将对缓存的修改操作立即写入内存
  3. 如果是写操作,它会导致其他CPU中对应的缓存行无效

  B),在修改变量的过程中

  1. 将修改变量的副本写入主内存
  2. 其他线程的 副本置为无效

C),读的时:先判断volatile关键字修饰的变量是否有效,有效直接读取,反之,则 到主内存获取最新值

有序性(能禁止指令重排序)

1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯 定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;

2)在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也 不能把volatile变量后面的语句放到其前面执行。

synchronized关键字

保证原子性 :synchronized关键字锁住的代码,一次只能被一个线程所操作。

保证可见性:在Java内存模型中,synchronized规定,线程在加锁时,先清空工作内存,在主存中拷贝最新变量的副本到工作内存,执行完代码后,将更改后的共享变量的值刷新到主内存中,释放锁。

保证有序性:synchronized通过“一个变量 在同一时刻只允许一个线程对它进行lock操作”,这条规则决定了持有同一个锁的两个同步块只能串行的并入

区别

1,volatile不会造成线程的阻塞,synchronized会。

2,synchronized会 造成线程状态的改变,而线程状态的改变又依赖于操作系统,所以效率会比较低。

3,synchronized可以修饰代码块、方法。volatile只能修饰变量。

4,synchronized能保证原子性、volatile不能。

5,volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

猜你喜欢

转载自blog.csdn.net/qq_37937537/article/details/82764667