Java中的volatile和synchronize
相关术语
名称 | 英文 | 释义 |
---|---|---|
内存屏障 | memory barriers | 对内存操作的顺序限制 |
缓冲行 | cache line | CPU高速缓存中可以分配的最小存储单位 |
比较并交换 | Compare and swap | CAS操作输入两个数值,旧值没有发生变化,才交换新值 |
CPU流水线 | CPU pipeline | 实现在一个CPU时钟周期完成一条指令 |
volatile的定义及实现
- 定义:Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。
- 实现原则:使用Lock汇编码,Lock前缀指令会引起处理器缓存回写到内存;一个处理器的缓存回写到内存回导致其他处理器的缓存无效。
- 使用优化:追加成64字节——Doug lea
synchronize的定义及实现
- 在JVM中的实现原理:给予进入和退出Monitor对象来实现方法同步和代码块同步,方法同步通过monitorenter和monitorexit指令实现。
- Java对象头:
名称 释义 Mark Word 存储对象的hashCode、锁信息、分代年龄 Class Metadata Address 对象类型数据的指针 Arrat length 数组长度
锁的升级
- 偏向锁:同一线程多次获得锁,在对象头和栈帧中的锁记录里存储偏向的线程ID。
- 撤销:使用了等到竞争出现才撤销的机制
- 关闭:通过设置JVM参数
- 轻量级锁:
- 加锁:访问同步块->分配空间并复制Mark Word到栈->CAS修改Mark Word,成功则替换为轻量级锁,失败则自旋。
- 解锁:使用CAS将Displaced Mark Word替换到对象头,若失败,表示锁存在竞争,升级为重量级锁。
- 三种锁的对比
名称 优点 缺点 场景 偏向锁 加锁解锁不许额外消耗 若线程间存在锁竞争,会带来锁撤销的消耗 使用以单一线程使用同步块 偏向锁 竞争的线程不会阻塞,提高相应速度 自旋会消耗CPU 追求相应时间,同步块执行速度非常快 重量级锁 献策好难过竞争不适用自旋,不消耗CPU 线程阻塞,相应时间缓慢 追求吞吐量,同步块执行时间长
原子操作的实现
- 实现机制:总线锁+缓存锁
- 总线锁:当处理器在总线上输出Lock信号,其他处理器的请求就被阻塞,该处理器可以独占共享内存
- 缓存锁:使用缓存一致性机制