jvm:CAS和锁

CAS与原子类

  • CAS:Compare and Swap,它体现的是一种乐观锁的思想;

    • 没有使用synchronized,不会陷入线程阻塞;
    • 但是如果竞争激烈,会频繁尝试,影响效率;
    • 必须配合volatile使用,拿到最新的值;
    //不断的利用CPU尝试,避免了阻塞等待;
    while (true) {
        int 旧值 = 共享变量; //必须配合volatile使用,拿到最新的值;
        int 结果 = 旧值;
        if (comareAndSwap(旧值, 结果)) {
            //旧值相同,返回true;
            //旧值不同,返回false,其他线程已修改;
        }
    }
    
  • 乐观锁:CAS,基于最乐观的估计,当别的线程修改,那就重新尝试【多核cpu】;

  • 悲观锁:synchronized,基于最悲观的估计,防止其他线程来修改共享变量,给它加上把锁,我用完了再开锁;

synchronized优化:

  • 每个对象投【class指针核Mark ward】,
    • Mark Word平时存储这个对象的:哈希码,分代年龄;
    • 当加锁的时候,就会替换为:标记位,线程锁记录指针,重量级锁指针,线程ID等;
    • 每一个线程的栈帧,都会包含一个锁记录的结构,当对象加锁的时候,可以替换对象的Mark Word;
  • 轻量级锁:多个线程访问的时间是错开的,当遇到线程同时访问的时候,会升级为重量级锁【无竞争】;
    1. 当无锁的时候,将mark word 复制给线程的锁记录,
    2. 使用CAS修改mark word 为锁记录地址;
    3. 修改锁状态;
  • 锁膨胀【存在竞争】:
    • 如果再尝试加轻量级锁的过程中,CAS操作无法成功【其他线程已经占用】,此时为就会将拥有锁的进行锁膨胀,升级为重量级锁;
    • 同时,尝试加锁的线程会阻塞;
    • 当拥有锁的,用轻量级解锁,失败,就释放重量级锁【唤醒阻塞线程】,开始竞争重量级锁;
  • 重量级锁:
    • 当线程陷入阻塞和唤醒时候,会降低效率;
    • 所以当重量级锁被占用时,会尝试自旋,在短时间内,再度查看锁状态,多次所还是没有释放,还是会陷入阻塞;
  • 偏向锁:
    • 对于锁重注,相同的锁,不同的们,都需要进行锁记录地址核mark word的交换的优化;
    • 优化:只有第一次使用的CAS将线程的ID设置到对象的markword头,之后发现这个线程id是自己就表示没有竞争,不需要重新CAS;
    • 缺点多;
  • 其他优化:
    • 减少上锁时间,防止升级锁;
    • 将一个锁,拆分为多个锁,并发度更高【减少锁的粒度】;
    • 锁粗化,;
    • 锁消除;
    • 读写分离;
posted @ 2025-03-20 15:48  烟雨断桥  阅读(29)  评论(0)    收藏  举报