java 代码在编译后会变成java字节码,字节码被类加载器加载到jvm里,jvm执行字节码,最终需要转化为汇编指令在cpu上执行,java中所使用的并发机制依赖于jvm的实现和cpu的指令,本章我们将深入底层一起探索java并发机制的底层实现原理
volatile 是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性和有序性,可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值,它比synchronized执行成本更低,没有上下文切换与调度
synchronized在并发编程中,应该说是元老级人物,很多人也称呼它为重量级锁,但在java1.6中进行了优化,引入偏向锁、轻量级锁
底层原理
monitorenter 指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束和异常处,jvm要保证每个monitorenter必须有对应的monitorexit与之配对,任何对象都有一个monitor关联,当且一个monitor被持有后,它将处于锁定状态,线程执行到monitorenter指令是,将会尝试获取对象锁对应monitor的所有权,即尝试获取锁。
java对象头
synchronized用的锁是存在java对象头里面,对象头里面的Mark word 存储对象的hashcode 、分代年龄和锁标记位
锁的升级
大多数情况,锁不仅不存在多线程竞争,总是由同一个线程获取,这时获得锁就是偏向锁。
如果遇到线程的竞争,偏向锁就会释放,变为轻量级锁,当出现有自旋,长时间获取不到,就变为重量级锁
java 是通过CAS方式实现原子操作
CAS:就是循环比较期望值与旧值,是否相等,相等则进行替换,不相等就一直循环尝试替换。
ABA问题:在cas方式操作值的时候,有可能出现,线程A与线程B,线程A对变量i=100进行修改200,再修改为100,那么线程B再修改A时发现,还是原来100,就会进行修改,这时就会出现了ABA问题
案例:假设你有存款1000元,你去银行转账500,转账成功了,但不小心又点一次次转账的之前,有人给你转了500,因为发现存款是1000,没有扣500,所以第二次误点转账也会成功(可能此案例不符合生活场景)。
为了解决这问题,每次转账都加一个版本号来区分是否原来的金额。