zoukankan      html  css  js  c++  java
  • synchronized中锁是怎么升级的

    在JDK1.6以前,使用synchronized就只有一种方式即重量级锁,而在JDK1.6以后,引入了偏向锁,轻量级锁,重量级锁,来减少竞争带来的上下文切换。

    锁升级主要依赖对象头中的Mark Word中的锁标志位和释放偏向锁标识位。

    一般的synchronized同步锁升级步骤是:偏向锁 -> 轻量级锁 -> 重量级锁。

    注意:锁只能升级,不能降级。

    img

    img

    偏向锁

    偏向锁,顾名思义是偏向某一个线程的锁,在该某个线程第一次成功锁时,会在对象头中存储所偏向的线程ID,如果下一次还是该线程获取锁,只需要在对象头Mark Word中去判断一下是否有偏向锁指向它的ID,大大减少了性能的消耗。

    什么时候升级为轻量级锁呢?

    当有另外一个线程竞争获取这个锁时,由于该锁已经是偏向锁,当发现对象头 Mark Word 中的线程 ID 不是自己的线程 ID,就会进行 CAS 操作获取锁,如果获取成功,直接替换 Mark Word 中的线程 ID 为自己的 ID,该锁会保持偏向锁状态;如果获取锁失败,代表当前锁有一定的竞争,偏向锁将升级为轻量级锁。

    轻量级锁

    轻量级锁是相对于重量级锁而言,轻量级锁不需要申请互斥量,只需要将Mark Word 中的部分字节CAS更新指向栈中锁记录的指针,如果更新成功,则轻量级锁获取成功,记录锁状态为轻量级锁;否则,说明已经有线程获取了轻量级锁,发生了锁竞争,轻量级锁开始自旋。

    自旋锁与自适应自旋锁

    自旋锁(包括自适应自旋锁)是轻量级锁在升级为重量级锁前做的最后一次挣扎。

    在JDK1.6之前设置自旋锁为自旋超过十次,或者等待线程超过cpu核数的2分之一,锁升级为重量级锁;

    在JDK1.6后优化为自适应的自旋锁,如果自旋超过一定次数,或者此时有第三个线程来竞争该锁时,锁升级为重量级锁。

    重量级锁

    重量级锁是如果多个线程同时竞争锁,只会有一个线程得到这把锁,其他线程获取锁失败,不会和轻量级锁进行自旋等待锁被释放,而是直接阻塞没有获取成功的线程。

    重量级锁需要操作系统对线程状态的切换,

    当锁升级为重量级锁后,未抢到锁的线程都会被阻塞,进入阻塞队列。

    总结

    synchronized的执行过程:

    1. 检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁
    2. 如果不是,则使用CAS将当前线程的ID替换Mard Word中的线程ID,如果成功则表示当前线程获得偏向锁,置偏向标志位1
    3. 如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
    4. 当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁
    5. 如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
    6. 如果自旋成功则依然处于轻量级状态。
    7. 如果自旋失败,则升级为重量级锁。
  • 相关阅读:
    梯度提升树(GBDT)原理小结
    scikit-learn Adaboost类库使用小结
    集成学习之Adaboost算法原理小结
    集成学习原理小结
    支持向量机高斯核调参小结
    scikit-learn 支持向量机算法库使用小结
    支持向量机原理(五)线性支持回归
    支持向量机原理(四)SMO算法原理
    支持向量机原理(三)线性不可分支持向量机与核函数
    支持向量机原理(二) 线性支持向量机的软间隔最大化模型
  • 原文地址:https://www.cnblogs.com/xbq8080/p/14512407.html
Copyright © 2011-2022 走看看