zoukankan      html  css  js  c++  java
  • volatile关键字简介

    volatile的作用

    • 保证变量在多线程中的可见性
    • 保证指令的有序性(禁止指令重排)

    保证变量在多线程中的可见性

    1. 主存中有一个变量a, 它被volatile关键字所修饰, 并且它的值是0

    2. T1T2线程读取了变量a, 此时它们的线程的本地内存(CPU寄存器或高速缓存)中的值都是0

    3. 如果T1修改了变量a的值为1, 由于被a变量被volatile所修饰, 那么T1修改之后的a就会被刷新到主存(写屏障), 并且执行T2线程的CPU对a变量的缓存行会失效(读屏障), 强制从主存中获取值, 到达了多线程中变量的可见性的目的

    4. 通过内存屏障保证变量在多线程中的可见性, 如果字段被volatile修饰:

      • 读屏障: 在读指令前插入读屏障,可以让高速缓存中的数据失效重新从主内存加载数据
      • 写屏障: 在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存

    保证指令的有序性(禁止指令重排)

    指令重排的意义

    • JVM能够根据CPU的特性(CPU的多级缓存系统、多核处理器等)适当的重新排序机器指令,使机器指令更符合CPU的执行特点,最大限度的发挥CPU的性能,提高效率。

    • 单线程情况下, 指令重排没问题, 但是多线程环境下, 指令重排可能造成程序的执行结果并不是我们所期待的, 比如单例模式的DCL写法对DCL单例模式的思考

    volatile通过两点保证指令有序性

    happens-before

    happens-before原则(定义一些禁止编译优化的场景,保证并发编程的正确性), 下图来源于: 来源《Java并发编程实践》

    内存屏障

    • 编译器生成字节码时, 会在指令序列中插入内存屏障,会多出一个 lock 前缀指令

    • 内存屏障是一组处理器指令,解决禁止指令重排序和内存可见性的问题,保证指令重排序后与之前的输出结果一 样,使性能得到优化, 处理器在进行重排序时是会考虑指令之间的数据依赖性

    • 先于这个内存屏障的指令必须先执行,后于这个内存屏障 的指令必须后执行

    使用 volatile 的经典场景

    • 双重校验锁 DCL(double checked locking)
    • ConcurrentHashMap哈希数组Node[]
    • 原子类例如AtomicIntegervalue属性
    • 多个线程操作同一块内存的同一个变量(保证有序性和内存可见性,有序性和可见性同等重要,都不能忽略)
  • 相关阅读:
    修改apache的默认访问目录
    禁止浏览器直接访问php文件
    使用Apache Bench进行压力测试
    关于mysql(或MariaDB)中的用户账号格式
    单表查询
    CSS设计指南之一 HTML标记与文档结构
    SQL SERVER技术内幕之10 可编程对象
    SQL SERVER技术内幕之10 事务并发
    观察者模式
    中介者模式
  • 原文地址:https://www.cnblogs.com/theRhyme/p/14589329.html
Copyright © 2011-2022 走看看