- 协议可以保证每个缓存中使用的共享变量的副本是一致的,原理:CPU对主存中的共享变量有写入操作时,会立即通知其他CPU将该变量缓存行置为无效状态 。其他CPU发现该变为无效状态时,就会重新去主存中读取该变量最新值 。
- 优点就是可以解决问题,读多写少效率还OK;缺点就是实现繁琐,较耗费性能,在对于写多的场景下效率很不可观
?答:共享资源不能及时同步更新,归根于 分时系统上下文切换时 指令还未执行完毕 (没有写回结果) 更新异常
引入并解释并发编程特性?众所周知现在的互联网大型项目,都是采用分布式架构同时具有其“三高症状”,高并发、高可用、高性能 。高并发为其中最重要的特性之一,在高并发场景下并发编程就显得尤为重要,其并发编程的特性为原子性、可见性、有序性 。
原子性指的是一个或多个操作要么全部执行成功要么全部执行失败,期间不能被中断,也不存在上下文切换,线程切换会带来原子性的问题 。
- 变量赋值问题:
- 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 关键字?
经验总结扩展阅读
- 香港北角到铜锣湾怎么走
- [CG从零开始] 4. pyopengl 绘制一个正方形
- 一文读懂Apache Geode缓存中间件
- 树马齿苋花怎么养
- 义乌到河北唐山快递要多久
- 为什么睡到半夜胃胀气
- 马栗乐真假区别?
- 韩国苏秘真假对比?
- 雨水的格言
- 跳棋怎么玩(跳棋怎么玩新手入门)