volatile原理分析

什么是 Volatile

能够保证线程可见性,当一个线程修改共享变量时,能够保证对另外一个线程可见性,

但是注意他不能够保证共享变量的原子性问题。

Volatile的特性

可见性

能够保证线程可见性,当一个线程修改共享变量时,能够保证对另外一个线程可见性,

但是注意他不能够保证共享变量的原子性问题。

顺序性

程序执行程序按照代码的先后顺序执行。

原子性

即一个操作或者多个操作 要么全部执行并且执行的过程,要么失败。

Volatile可见性

public class Mayikt extends Thread {
    /**
     * lock 锁 汇编的指令 强制修改值,立马刷新主内存中 另外线程立马可见刷新主内存数据
     */
    private static volatile boolean FLAG = true;

    @Override
    public void run() {
        while (FLAG) {

        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Mayikt().start();
        Thread.sleep(1000);
        FLAG = false;
    }
}

 

 

CPU多核硬件架构剖析

CPU每次从主内存读取数据比较慢,而现代的CPU通常涉及多级缓存,CPU读主内存

按照空间局部性原则加载 局部快到缓存中。

并发编程第3篇,volatile原理分析(一)

 

 

为什么会产生可见性的原因

因为我们CPU读取主内存共享变量的数据时候,效率是非常低,所以对每个CPU设置

对应的高速缓存 L1、L2、L3  缓存我们共享变量主内存中的副本。

相当于每个CPU对应共享变量的副本,副本与副本之间可能会存在一个数据不一致性的问题。

比如线程线程B修改的某个副本值,线程A的副本可能不可见。导致可见性问题。

 

CPU的摩尔定律

https://baike.baidu.com/item/%E6%91%A9%E5%B0%94%E5%AE%9A%E5%BE%8B/350634?fr=aladdin

基本每隔18个月,可能CPU的性能会提高一倍。

 

JMM内存模型

Java内存模型定义的是一种抽象的概念,定义屏蔽java程序对不同的操作系统的内存访问差异。

 

主内存:

  存放我们共享变量的数据

工作内存:

  每个CPU对共享变量(主内存)的副本。堆+方法区

JMM八大同步规范

并发编程第3篇,volatile原理分析(一)

 

(1)lock(锁定):作用于 主内存的变量,把一个变量标记为一条线程独占状态

(2)unlock(解锁):作用于 主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

(3)read(读取):作用于 主内存的变量,把一个变量值从主内存传输到线程的 工作内存中,以便随后的load动作使用

(4)load(载入):作用于 工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中

(5)use(使用):作用于 工作内存的变量,把工作内存中的一个变量值传递给执行引擎

(6)assign(赋值):作用于 工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量

(7)store(存储):作用于 工作内存的变量,把工作内存中的一个变量的值传送到 主内存中,以便随后的write的操作

(8)write(写入):作用于 工作内存的变量,它把store操作从工作内存中的一个变量的值传送到 主内存的变量中

 

Volatile汇编lock指令

  1. 将当前处理器缓存行数据立刻写入主内存中。
  2. 写的操作会触发总线嗅探机制,同步更新主内存的值。

Java汇编指令查看

E:\java8\jdk\jre\bin\server 放入 hsdis-amd64.dll

首先需要将jar包

-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*Mayikt.*

 

 0x0000000002ae6277: lock addl $0x0,(%rsp)     ;*putstatic FLAG

                                                ; - com.mayikt.Mayikt::[email protected] (line 24)

 

 

Volatile的底层实现原理

通过汇编lock前缀指令触发底层锁的机制

锁的机制两种:总线锁/MESI缓存一致性协议

主要帮助我们解决多个不同cpu之间三级缓存之间数据同步

 

总线锁

当一个cpu(线程)访问到我们主内存中的数据时候,往总线总发出一个Lock锁的信号,其他的线程不能够对该主内存做任何操作,变为阻塞状态。该模式,存在非常大的缺陷,就是将并行的程序,变为串行,没有真正发挥出cpu多核的好处。

MESI协议

1.M 修改 (Modified) 这行数据有效,数据被修改了,和主内存中的数据不一致,数据只存在于本Cache中。

2.E 独享、互斥 (Exclusive) 这行数据有效,数据和主内存中的数据一致,数据只存在于本Cache中。

3.S 共享 (Shared) 这行数据有效,数据和主内存中的数据一致,数据存在于很多Cache中。

4.I 无效 (Invalid) 这行数据无效。

 

E:独享:当只有一个cpu线程的情况下,cpu副本数据与主内存数据如果

保持一致的情况下,则该cpu状态为E状态 独享。

S:共享:在多个cpu线程的情况了下,每个cpu副本之间数据如果保持一致

的情况下,则当前cpu状态为S

M:如果当前cpu副本数据如果与主内存中的数据不一致的情况下,则当前cpu状态

为M

I: 总线嗅探机制发现 状态为m的情况下,则会将该cpu改为i状态 无效

该cpu缓存主动获取主内存的数据同步更新。

总线:维护解决cpu高速缓存副本数据之间一致性问题。

如果状态是M的情况下,则使用嗅探机制通知其他的CPU工作内存副本状态为I无效状态,则 刷新主内存数据到本地中,从而多核cpu数据的一致性。

 

每一行代码都有它的涵义,多问一句为什么;别怕,理清思路,一切代码都是数据的流动和转化,耐心一点,慢慢积累!一起加油!!!

相关文章:

  • 2022-12-23
  • 2021-10-21
  • 2021-05-24
  • 2022-12-23
  • 2021-08-21
  • 2022-12-23
  • 2022-02-17
  • 2021-11-17
猜你喜欢
  • 2021-05-24
  • 2021-08-30
  • 2021-09-09
  • 2021-04-22
  • 2021-09-11
  • 2022-12-23
  • 2021-06-30
相关资源
相似解决方案