# Volatile

volatile 是轻量级的 synchronized,它在多处理器开发中保证了共享变量的 “可见性”。可见性的意思是当一个线程 修改一个共享变量时,另外一个线程能读到这个修改的值。

instance = new Singleton(); //instance 是 volatile 变量
// 汇编代码
0x01a3de1d: movb $0×0,0×1104800(%esi);0x01a3de24: lock addl $0×0,(%esp);
  1. Lock 前缀的指令,将这个变量所在缓存行的数据 写回到系统内存。
  2. 其他 CPU 里缓存了该内存地址的数据无效,对数据的访问需要从内存重新读取。(处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了)

# Synchronized

monitorenter 指令是在编译后插入到同步代码块的开始位置,而 monitorexit 是插入到方法结束处和异常处.

synchronized 用的锁是存在 Java 对象头的 Mark Word

# Mark Word 结构

TODO: 结构和状态值表

锁状态记录是否偏向锁锁标记位
轻量级锁指向栈中锁记录的指针00
重量级锁指向互斥量(重量级锁)的指针10
GC11
偏向锁线程 ID101

# 锁升级

锁一共有 4 种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状 态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,

  1. 单一线程频繁获得锁
    当一个线程访问同步块并 获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程 ID,以后该线程在进入和退出 同步块时不需要进行 CAS 操作来加锁和解锁,只需简单地测试一下对象头的 Mark Word 里是否 存储着指向当前线程的偏向锁。如果测试成功,表示线程已经获得了锁。如果测试失败,则需 要再测试一下 Mark Word 中偏向锁的标识是否设置成 1 (表示当前是偏向锁): 如果没有设置,则 使用 CAS 竞争锁;如果设置了,则尝试使用 CAS 将对象头的偏向锁指向当前线程。

  2. 轻量级锁
    线程在执行同步块之前,JVM 会先在当前线程的栈桢中创建用于存储锁记录的空间,并 将对象头中的 Mark Word 复制到锁记录中,官方称为 Displaced Mark Word。然后线程尝试使用 CAS 将对象头中的 Mark Word 替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失 败,表示其他线程竞争锁,当前线程便尝试使用 CAS 自旋来获取锁,失败则升级为重量级锁。

  3. 重量级锁
    轻量级锁的线程释放锁后,通知等待重量级锁的线程。

# 原子性

# CAS

存在问题:

  1. ABA 问题
  2. 循环时间长开销大
  3. 只能保证一个共享变量的原子操作

# Lock

# JMM

Java 线程之间的通信由 Java 内存模型 (本文简称为 JMM) 控制,JMM 决定一个线程对共享 变量的写入何时对另一个线程可见 可见性。从抽象的角度来看,JMM 定义了线程和主内存之间的抽 象关系:线程之间的共享变量存储在主内存 (Main Memory) 中,每个线程都有一个私有的本地 内存 (Local Memory),本地内存中存储了该线程以读 / 写共享变量的副本。本地内存是 JMM 的 一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优 化。

# 有序性

Edited on Views times

Give me a cup of [coffee]~( ̄▽ ̄)~*

文理兼修电脑首席 WeChat Pay

WeChat Pay

文理兼修电脑首席 Alipay

Alipay