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

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

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

  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
posted @   Vincent-yuan  阅读(257)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示