面试知识库

synchronized → volatile/JMM → CAS/AQS 追问链#

追问路径#

涉及知识点#

核心串联逻辑#

  1. synchronized锁升级:JDK6前直接用Monitor重量级锁(涉及用户态/内核态切换),优化后从偏向锁→轻量级锁(CAS)→重量级锁逐级升级,单线程或低竞争场景几乎零开销
  2. volatile三大语义:保证可见性(MESI)、禁止重排序(内存屏障),但复合操作(如i++)不原子
  3. JMM是契约:happens-before给出无需关心底层屏障就能推导可见性的高层规则,DCL靠volatile阻止”赋引用”重排到”初始化”前
  4. CAS到AQS的演进:CAS是单变量无锁原语 → LongAdder用分段把热点CAS打散 → AQS用state+队列把CAS扩展成可阻塞的通用锁框架
  5. 代码示例
    // DCL单例:volatile防止半初始化对象逃逸
    public class Singleton {
        private static volatile Singleton INSTANCE;  // 必须volatile
        public static Singleton get() {
            if (INSTANCE == null) {                  // 第一次检查,避免每次加锁
                synchronized (Singleton.class) {
                    if (INSTANCE == null)            // 第二次检查,防重复创建
                        INSTANCE = new Singleton();
                }
            }
            return INSTANCE;
        }
    }
    java

面试回答串联#

30秒速答#

“synchronized靠对象头Mark Word关联Monitor,JDK6后做了偏向锁→轻量级锁→重量级锁的升级优化。volatile保证可见性和有序性但不保证原子性,靠内存屏障和lock指令实现,背后是JMM的happens-before语义。CAS是无锁原子操作但有ABA和自旋问题,AQS用volatile state加CLH队列把CAS封装成ReentrantLock这类可阻塞锁。“

2分钟展开答#

“synchronized底层是对象头Mark Word关联Monitor对象,通过monitorenter/monitorexit字节码加解锁。JDK6引入锁升级避免一上来就用重量级锁:无竞争时偏向锁记录线程ID,出现竞争升级为轻量级锁做CAS自旋,自旋失败再升级为重量级锁阻塞——只升不降。偏向锁在JDK15被废弃,因为撤销要STW、现代应用普遍有竞争。volatile保证可见性和禁止重排序但不保证原子性:写后插StoreLoad屏障、底层lock前缀指令触发MESI缓存一致性强制刷主存。可见性的理论基础是JMM的happens-before——它定义了程序顺序、锁、volatile、传递性等规则,是判断一个写对另一个读是否可见的依据。典型应用是DCL单例必须给instance加volatile,否则new对象的’分配内存→初始化→赋引用’三步可能重排序,导致其他线程拿到非空但未初始化的对象。无锁方向上,CAS靠cmpxchg指令实现,但有ABA(加版本号解决)、自旋空转(LongAdder分段累加+@Contended避免伪共享)、只能保单变量三个问题。AQS就是用一个volatile的state加CLH双向队列,把CAS扩展成可阻塞、可排队的通用同步框架,ReentrantLock、CountDownLatch、Semaphore都基于它。ReentrantLock相比synchronized支持可中断、超时tryLock、公平锁和多Condition,但要手动unlock。“

相关追问链#