多线程的共享变量的内存不可见性
线程的开销 :
- 线程的创建和销毁
- 线程的上下文切换和调度
- 线程的同步
多线程的内存模型: 线程独有的工作内存(线程缓存用于提高效率)---------所有线程共享的主内存
线程读取在主内存的成员变量(即共享变量)的过程:
- 线程的工作内存会去读取主内存的成员变量并保存副本
- 线程在工作内存中修改副本
- 将修改后的副本的值推送给主空间并改写主空间该成员变量的值
- 主空间成员变量修改后的值将不会主动推送给其他线程, 这就造成了线程的工作内存的共享变量的不同步
问题: 各个线程的工作内存不可见
即 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
原文地址:https://www.cnblogs.com/Vincent-yuan/p/15004368.html
- React Native入门(二)Atom+Nuclide安装、配置与调试
- React Native入门(一)环境搭建与Hello World
- android 自定义Viewpager实现无限循环
- Android内存优化(二)DVM和ART的GC日志分析
- Android Material Design之Toolbar与Palette实践
- android-async-http框架源码分析
- 使用Buck构建Android工程
- android 实现淘宝收益图的折线
- React Native入门(三)组件的Props(属性)和State(状态)
- Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)【Dalston版】
- PNG图片压缩对比分析
- 关于M4A文件的随机访问
- (whh仅供自己参考)进行ip网络请求的步骤
- HTML中的javascript交互
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 科学与艺术的融合:遗传算法绘制蒙娜丽莎
- “工业听诊”中多声源事件检测与定位
- 工业党福利:使用PaddleX高效实现指针型表计读取系列文章(2)
- 【三维点云系列】PCL点云库之数据文件与IO操作
- Jvm故障处理工具
- 递增子序列
- redis学习(二)
- You-Get 使用方法
- 接口测试 Mock 实战 | 结合 jq 完成批量化的手工 Mock
- 在Angular应用的child Component里同时使用@Input和@Output
- Angular应用里的@Input和@Output注解使用方法介绍
- K8S Ingress使用|常见问题列表
- 部署Tomcat及负载均衡
- Jenkins常用插件Publish Over SSH
- Zabbix 4.0配置监控Linux客户端