原子性指的是一个或多个操作要么全部执行成功要么全部执行失败,期间不能被中断,也不存在上下文切换,线程切换会带来原子性的问题 。
- 变量赋值问题:
- b 变量赋值的底层字节码指令被分为两步:第一步先定义 int b;第二步再赋值为 10 。
- 两条指令之间不具有原子性,且在多线程下会发生线程安全性问题
int b = 10;
- b 变量赋值的底层字节码指令被分为两步:第一步先定义 int b;第二步再赋值为 10 。
例如上述变量在读写场景下,不能保证其可见性,导致写线程完成修改指令时但为同步到主存中 , 读线程并不能获得最新值 。这就是对于B线程来说没有满足可见性 。
- 案例解析:final关键字
- final 变量可以保证其他线程获取的该变量的值是唯一的 。变量指成员变量或者静态变量
- b 变量赋值的底层字节码指令被分为两步:第一步先定义 int b;第二步再赋值为 10
final a = 10;int b = 10;
- final修饰的变量在其指令后自动加入了写屏障 , 可以保证其变量的可见性
- a 可以保证其他线程获取的值唯一;b 不能保证其他线程获取到的值一定是 10 , 有可能为 0 。
- 读取 final 变量解析 :
- 不加 final 读取变量时去堆内存寻找,final 变量是在栈空间,读取速度快
- 读取 final 变量时,直接将其在栈中的值复制一份 , 不用去 getstatic ,性能得到提升
- 注意:不是所有被 final 修饰的变量都在栈中 。当数值超过变量类型的 MAX_VALUE 时,将其值存入常量池中
- 读取变量的速度:栈 > 常量池> 堆内存
- final 变量可以保证其他线程获取的该变量的值是唯一的 。变量指成员变量或者静态变量
- final 可以加强线程安全,而且符合面向对象编程开闭原则中的close,例如子类不可继承、方法不可重写、初始化后不可改变、非法访问(如修饰参数时,该参数为只读模式)等
在Java中有序性问题会时常出现,由于我们的JVM在底层会对代码指令的执行顺序进行优化(提升执行速度且保证结果),这只能保证单线程下安全,不能保证多线程环境线程安全,会导致指令重排发生有序性问题 。
案例:排名世界第一的代码被玩坏了的单例模式
DCL(double checked):加入 volatile 保证线程安全,其实就是保证有序性 。
上代码:其中包括了三个问题并且有详细注释解释 。(鸣谢itheima满一航老师)
- 为什么加入 volatile 关键字?
- 对比实现3(给静态代码块加synchronized) 说出这样做的意义?
- 为什么要在这里加空判断,之前不是判断过了吗?
final class SingletonLazyVolatile {private SingletonLazyVolatile() { }// 问题1:为什么加入 volatile 关键字?// 答:防止指令重排序 造成返回对象不完整 。如 TODOprivate static volatile SingletonLazyVolatile INSTANCE = null;// 问题2:对比实现3(给静态代码块加synchronized) 说出这样做的意义?// 答:没有锁进行判断、效率较高public static SingletonLazyVolatile getInstance() {if (INSTANCE != null) {return INSTANCE;}// 问题3:为什么要在这里加空判断,之前不是判断过了吗?// 答:假入t1 先进入判断空成立,先拿到锁 , 然后到实例化对象这一步(未执行)//同时 线程 t2 获取锁进入阻塞状态,若 t1 完成创建对象后 , t2 没有在同步块这进行判空,t2 会再新创建一个对象,//导致 t1 的对象被覆盖 造成线程不安全 。synchronized (SingletonLazyVolatile.class) {// t1if (INSTANCE != null) {return INSTANCE;}INSTANCE = new SingletonLazyVolatile();// t1这行代码会发生指令重排序,需要加入 volatile// 如:先赋值指令INSTANCE = new SingletonLazyVolatile , 导致实例不为空,下一个线程会判空失败直接返回该对象// 但是构造方法()指令还没执行,返回的就是一个不完整的对象 。return INSTANCE;}}}
通过对并发编程的三要素介绍,也就是说,要想并发程序正确地执行,必须要保证原子性、可见性以及有序性 。只要有一个没有被保证,就有可能会导致程序运行不正确 。补充volatile知识:
volatile
只保证可见性(多线程下对变量的修改是可见的)、有序性(禁止进行指令重排序)
- volatile 的底层实现原理是内存屏障(内存栅栏) , Memory Barrier(Memory Fence),内存屏障会提供3个功能:
推荐阅读
- [CG从零开始] 4. pyopengl 绘制一个正方形
- 一文读懂Apache Geode缓存中间件
- 跳棋怎么玩(跳棋怎么玩新手入门)
- 跳跳棋怎么玩(跳棋怎么玩新手入门)
- [CG从零开始] 3. 安装 pyassimp 库加载模型文件
- 塔罗牌该怎样入门(塔罗入门禁忌)
- 网购的兔子怎么养(从小摊买的兔子怎么养)
- 企业运维 | MySQL关系型数据库在Docker与Kubernetes容器环境中快速搭建部署主从实践
- 如何0到1构建DevOps?
- 小米11Ultra发热严重_小米11Ultra发热严重官方回应