首页 > 其他分享 >Volatile介绍

Volatile介绍

时间:2022-08-20 10:11:48浏览次数:40  
标签:变量 指令 介绍 屏障 线程 内存 操作 Volatile

介绍

volatile 是 Java 虚拟机提供的轻量级的同步机制,它可以保证可见性(缓存一致性协议)和有序性(禁止指令重排序,也就是通过内存屏障来实现),但是不保证原子性。


JMM

介绍

JMM 是一个抽象的概念,它描述的是一种规范。这些规范定义了程序中各种变量的访问规则。
JMM 定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本。

规定

所有的共享变量都存储于主内存。这里所说的变量指的是实例变量和类变量,不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。
每一个线程还存在自己的工作内存,线程的工作内存,保留了被线程使用的变量的工作副本。
线程对变量的所有的操作(读,写)都必须在工作内存中完成,而不能直接读写主内存中的变量。
不同线程之间也不能直接访问对方工作内存中的变量,线程间变量值的传递需要通过主内存中转来完成。

8种原子操作

lock(锁定):作用于主内存的变量,把一个变量标识为线程独占状态。
read(读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
load(载入):作用于工作内存的变量,它把read操作从主存中得到变量放入工作内存的变量副本中。
use(使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。
assign(赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值赋值给工作内存的变量副本中,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
store(存储):作用于工作内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用。
write(写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。
unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。

图示


Happens-Before 原则

介绍

happens-before 原则,是 JMM 中非常重要的一个原则,它是判断数据是否存在竞争、线程是否安全的主要依据,依靠这个原则,我们可以解决在并发环境下两个操作之间是否存在冲突的所有问题。JMM 规定,两个操作存在 happens-before 关系并不一定要 A 操作先于B 操作执行,只要 A 操作的结果对 B 操作可见即可。

内容

程序顺序原则:一个线程内保证语义的串行性
volatile规则:volatile变量的写操作,先发生于读操作,这保证了volatile变量的可见性
锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
传递性:A先于B,B先于C,那么A必然先于C
线程的start()方法先于它的每一个动作
线程的所有操作先于线程的终结(Thread.join())
线程的中断(interrupt)先于被中断线程的代码
对象的构造函数执行、结束先于finalize()方法


volatile与内存屏障

内存屏障

内存屏障其实也是一种JVM指令,Java内存模型的重排规则会要求Java编译器在生成JVM指令时插入特定的内存屏障指令,通过这些内存屏障指令来禁止特定的指令重排序。
另外内存屏障还具有一定的语义:内存屏障之前的所有写操作都要回写到主内存,内存屏障之后的所有读操作都能获得内存屏障之前的所有写操作的最新结果(实现了可见性)。因此重排序时,不允许把内存屏障之后的指令重排序到内存屏障之前。

内存屏障的功能

1 确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2 强制将对缓存的修改操作立即写入主存,利用缓存一致性机制,并且缓存一致性机制会阻止同时修改由两个以上CPU缓存的内存区域数据;
3 如果是写操作,它会导致其他CPU中对应的缓存行无效。

[☛ 重点:这里就是配合总线嗅探的地方了,通过内存屏障保证有序性的同时也保证修改的变量要及时写回主内存]

内存屏障种类

Volatile读写内存屏障详情

StoreStore
Volatile 写
StoreLoad (保证写入对所有处理器可见)

Volatile 读
LoadLoad
LoadStore


为什么无法保证原子性?

在插入内存屏障之前的操作并不是原子性的。多个线程可以修改,所以无法保证原子性。


常见应用

状态标记

public class VolatileDemo {
    private static volatile boolean isOver = false;

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!isOver) 
            }
        });
        thread.start();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        isOver = true;
    }
}

double check(单例模式)

public class SingletonExample5 {
    // 私有构造函数
    private SingletonExample5() {}
    // 单例对象 volatile + 双重检测机制 -> 禁止指令重排
    private volatile static SingletonExample5 instance = null;
    // 静态的工厂方法
    public static SingletonExample5 getInstance() {
        if (instance == null) { // 双重检测机制
            synchronized (SingletonExample5.class) { // 同步锁
                if (instance == null) {
                    instance = new SingletonExample5();
                }
            }
        }
        return instance;
    }
}

标签:变量,指令,介绍,屏障,线程,内存,操作,Volatile
From: https://www.cnblogs.com/gustavo/p/16607223.html

相关文章

  • Condition介绍
    ConditionCondition是一种多线程通信工具,表示多线程下参与数据竞争的线程的一种状态,主要负责多线程环境下对线程的挂起和唤醒工作。方法//==========阻塞==========......
  • ThreadLocal介绍
    介绍ThreadLocal是一个线程变量工具类,提供了线程局部变量,就是为每一个使用该变量的线程都提供一个变量值的副本。我们可以利用ThreadLocal创建只能由同一线程读和写的变量......
  • Rust实战系列-Rust介绍
    “学习资料:rustinaction[1]1.Rust安装curl--proto'=https'--tlsv1.2-sSfhttps://sh.rustup.rs|shsource"$HOME/.cargo/env"2.helloworld创建hel......
  • monodepth2学习1-原理介绍
    monodepth2介绍monodepth2是在2019年CVPR会议上提出的一种三维重建算法,monodepth2是基于monodepth进行了改进,采用的是基于自监督的神经网络,提出了一下三点优化:一个最小......
  • 逻辑分析仪的简单使用介绍(附带i2c、串口、spi数据分析)
    本次文章给大家介绍一种便宜好用的协议分析工具,逻辑分析仪,首先声明,小飞哥作这篇介绍文章,不是为了打广告哈,实在是因为这个小玩意很好用,有些小伙伴还不太清楚该如何使用!!!废话......
  • 易基因:原核转录组测序(mRNA+sRNA)技术介绍|技术推介
    大家好,这是专注表观组学十余年,领跑多组学科研服务的易基因。 原核转录组测序可以从基因表达量、基因结构和sRNA调控功能三维度揭示不同生物性状的分子调控机制。如通过......
  • ZAB协议介绍
    什么是Zab协议ZAB协议,全称ZookeeperAtomicBroadcast(Zookeeper原子广播协议)。它是专门为分布式协调服务——Zookeeper,设计的一种支持崩溃恢复和原子广播的协议。从设......
  • Angular forRoot 方法的使用场合介绍
    forRoot()方法返回一个NgModule及其提供者Providers依赖项。NgModuleforRoot()约定对Angular初学者来说是一个奇怪的约定:命名说明了如何使用它,但没有说明这样做......
  • Mybatis核心配置文件中的标签介绍
    0.标签顺序Mybatis核心配置文件中有很多标签,它们谁谁写在前写在后其实是......
  • 防抖和节流的介绍及实现
    防抖概述:在规定时间内只执行一次(执行最后一次)举个例子:电梯关门案例a进入电梯等待5s后就可以上升了在a等待了4s中后b过来那么之前的等待就结束了开始新的等待......