• 多线程的共享变量的内存不可见性


    线程的开销 :
    • 线程的创建和销毁
    • 线程的上下文切换和调度
    • 线程的同步
    多线程的内存模型: 线程独有的工作内存(线程缓存用于提高效率)---------所有线程共享的主内存

    线程读取在主内存的成员变量(即共享变量)的过程:

    1. 线程的工作内存会去读取主内存的成员变量并保存副本
    2. 线程在工作内存中修改副本
    3. 将修改后的副本的值推送给主空间并改写主空间该成员变量的值
    4. 主空间成员变量修改后的值将不会主动推送给其他线程, 这就造成了线程的工作内存的共享变量的不同步
    问题: 各个线程的工作内存不可见
      即 A线程先读取共享变量a, B线程修改了共享变量a后为a`,推送给主内存并改写, 主内存不会推送给A线程,A和B的变量会不同步

    解决办法

    • synchroized可以同步值
    • volatile关键字 会使得主内存的共享变量每经过一次改变都会推送给其他的线程, 其他线程会修改其副本

    同步值之synchronized和volatile的区别
    相同点:
      synchronized 和 volatile都能用来同步共享变量
    不同点:
      1. volatile是轻量级的同步策略, 可以修饰基本类型的变量,如int, synchronized是重量级的同步策略,基于对象的同步锁
      2. volatile不具备互斥性, 一个线程访问共享变量 , 其他线程也可以访问共享变量
        synchronized是互斥锁, 具备互斥性, 在被锁的代码块上只能有一个线程访问共享变量

      3. volatile不能保证变量的原子性, 即一组对共享变量的操作不具备事务(要么全部完成,要么全部不完成) 如 i++/i--
    即一个线程在进行一组操作中还没完成时, 其他线程也能进入这组操作对共享变量进行修改
    而 synchronized则能保证一组对共享变量操作的原子性, 即这组操作全部完成,才能进行下一轮操作
    即在被锁的代码块中只能允许一个线程去执行这组操作, 其他需要执行这组操作的线程会进入阻塞状态,等待其完成

    总结:

    主内存    工作内存
    共享变量   副本
    工作内存中会主动去拉取主内存的共享变量并创建其副本
    工作内存中的副本修改后会推送给主内存改写共享变量
    volatile 会使得主内存修改后的共享变量推送其他线程

    内存不可见的本质 : 线程之间有互相独立的缓存区, 当多个线程对共享数据进行操作时, 其操作彼此不可见

    可以直接理解: 使用volatile之后该共享该变量线程不在工作内存缓存其副本, 所有线程对该变量的操作全是在主内存中完成
    即不在存在操作的不可见,所有线程的操作的变量是位于主内存的变量

    https://www.cnblogs.com/huangleshu/p/10026222.html
  • 相关阅读:
    leetcode 202 Happy Number
    【C++】函数缺省参数的作用
    【C++】类的两种实例化方法
    【C++】const 常引用的用法
    【Ubuntu】使用root账户登录ubuntu
    【Docker】基本命令使用介绍
    【Ajax】PHP中ajax的基本知识点
    【PHP】mysql基本操作整合
    一条命令搞定在VMware中的Ubuntu14.04 64 位安装Docker
    Java泛型初探
  • 原文地址:https://www.cnblogs.com/Vincent-yuan/p/15004368.html
Copyright © 2020-2023  润新知