持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
原子性、可见性、有序性
优化: CPU高速缓存的速度差异、分时复用CPU、优化指令执行顺序
硬件上的一些优化会导致这些问题
不可见性
原子性
有序性
处理器之间的指令编译重排序
Java内存模型
Java内存模型是一种抽象结构,他提供了合理的禁用缓存一级禁止重排序的方法来解决可见性、有序性问题
提供了合理的禁用缓存一级禁止重排序的方法来解决可见性、有序性问题
内存屏障
同步关键字synchronized
可以解决可见性、原子性、有序性
可以加在代码块上,也可以加在方法上
锁实例对象
第二个框里的锁的范围可以控制
synchronized的本质
synchronized的优化
volatile关键词分析
作用:
上面讲到不可见性的时候,定义了一个boolean值stop,但是线程读不到,所以停不下来,但是:
就变成可见性了
可见性
原理:
禁用缓存
将当前处理器缓存行的数据写回系统内存
这个写回的操作会使其他CPU里缓存的该内存地址的数据无效
什么情况下用到volatile
有序性
volatile如何解决有序性问题?
指令重排序
x86结构下面提供了CPU层面的内存屏障:
本质上来说: volatile实际上是通过内存屏障来防止指令重排序以及 禁止cpu高速缓存来解决可见性问题。 而#ock指令,它本意上是禁止高速缓存解决可见性问题,但实际上在 这里,它表示的是种内存屏障的功能。也就是说针对当前的硬件环境, JMM层面采用Lock指令作为内存屏障来解决可见性问题
final域
final域的重排序规则:
在引用变量被任意线程可见之前,这个引用变量指向的对象的final域已经在构造函数中被正确初始化过
还有一个保障是在构造函数内部,不能让这个这个变量引用被其他线程可见

Happens-Before规则
可以理解为编译器自带的一些禁止重排序的规则
指令执行顺序会优化,导致可见性问题,但是HB规则的语句不会
程序顺序规则
as-if-serial
单线程中不管怎么重排序, 单线程的执行结果是不会改变的。
编译器、处理器都要遵守asifserial语义,不会对有数据依赖关系的数据重排序
监视器锁规则
这个是理所当然的“规则”
volatile变量规则
对一个volatile域的写,hb于任意后续对这个volatile域的读
传递性
start()规则
join()
其他线程读到之后,var还是66
原子类Atomic
无锁工具的典范
// 参数是初始大小
private static AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.incrementAndGet();
因为加锁势必会带来性能问题,所以无锁化编程
实现原理
valueOFFset是: 这个原子类在内存中的偏移量
unsafe中的方法:
类似乐观锁
里面一直在循环,在执行,这里的性能消耗可以忽略
只有等offset(value)等于了expect才会跳出循环
还有很多原子类:
ThreadLocal实现原理
Demo:
这里的每个线程的结果都是不确定的
比如这里希望每个线程刚开始的时候都拿到的是0
可以看到这里线程之间产生隔离了,值设置回去了也不会对其他线程产生影响
实现原理
如果map为空

上面有计算hashcode的过程
也包含一些,动态扩容、清除空key的等等......