volatile的定义与实现原理
先了解CPU的术语:内存屏障、缓冲行、原子操作、缓冲行填充、缓存命中、写命中、写缺失
可见性:java线程内存模型确保所有线程看到这个变量的值是一致的
Lock前缀的指令在多核处理器会引发两件事情:
1)将当前处理器缓存行的数据
2)写回操作会使在其他CPU里缓存了该内存地址的数据无效
volatile的使用优化
追加64字节能够提高并发编程的效率:避免头节点和尾节点加载到同一个缓存行,使头、尾节点在修改时不会互相锁定
以下两种方式不应该使用追加64字节:
1)缓存行非64字节宽的处理器
2)共享变量不会被频繁地写(锁的几率小)
synchronized的实现原理与应用
synchronized有以下3种形式:
1.普通同步方法,锁是当前实例对象
2.静态同步方法,锁的是当前类的class对象
3.对于同步方法块,锁是synchronized括号里配置的对象
同步方法块用monitorenter与monitorexit指令实现,一个对象与一个monitor相关联,被持有后处于锁定状态。线程执行到时,尝试获取此monitor的所有权,即尝试获的对象的锁。
java对象头
synchronized用的锁是存在java对象头的,如果对象是数组类型,虚拟机用3个字宽存储对象头,非数组用2个字宽。
锁的分级与对比
锁有4种状态:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,级别只能从低到高
只有一个线程时,无竞争关系,用偏向锁
轻量级锁加锁和解锁
原子操作的实现原理
了解术语:比较和交换、CPU流水线、内存顺序冲突(假共享:多个cpu修改同一缓存行的不同部分引起一个cpu修改失效。cpu必须清空流水线)
处理器实现原子操作:
1)使用总线锁保证原子性
2)使用缓存锁保证原子性
第二种不适用的情况:
1)操作的数据不能缓存在处理器内部,或操作的数据跨多个缓存行
2)有些处理器不支持缓存锁定
CAS实现原子操作的三大问题
1)ABA问题。可能之前变换有换回来了。解决思路是版本号。JDK的Atomic包提供了一个类AtomicStampedReference来解决,对比预期标志和预期引用
2)循环时间长,开销大
3)只能保证一个共享变量的原子操作
使用锁机制实现原子操作(除了偏向锁之外,jvm实现锁的机制都用了循环CAS