Synchronized 锁升级

Synchronized是JAVA锁的一种形式,是基于JVM层面进行实现。主要有两种用法

  • 修饰方法
    • 在实现时,class文件有特殊标识符ACC_SYNCHRONIZED作用于同步方法
  • 修饰代码块
    • 在实现时,class文件会有两条指令monitorenter及monitorexit,作用于代码块之间

在jdk6之后Synchrozied 升级了,具有多种锁的形式,偏向锁,轻量级锁,自旋锁,及重量级锁。这几种锁之间是只升不降。

即偏向锁可以升级为轻量级锁,但是轻量级锁不能降低为偏向锁。接下来我们来看看锁是怎么升级的。

首先来看看一个作用于Synchronized对象是怎么表示"被获得锁的",主要是用对象头的32个字节来标识的。接下来我们借用一张图,来看看对象头。

当锁处于不同时期的时候,这32个字节所存在的内容也是不一样的。

当一个线程要获得锁的时候,是从偏向锁开始的。首先判断该对象头是否处于无锁状态或者偏向锁状态,如果是则利用CAS操作将对象头的线程ID替换为当前ID,如果CAS操作成功,则代表获得偏向锁。如果失败则证明当前偏向锁被其他线程获得,需要注意的是偏向锁并不会主动释放,所以我们先看看获得该锁的线程是否存活,如果死了,就想锁置为无锁状态或者指向当前线程,如果线程存活,我们就去该线程的栈中看看锁记录是否还需要占用当前锁(这一步是我认为的),如果不占用,那还是置为无锁状态或者指向当前线程。如果占用,jvm 会再安全点释放偏向锁,并升级为轻量级锁。

当线程获得轻量级锁时,首先会将对象头的markword字段复制到本线程的栈帧的锁记录空间中,并利用cas操作将原markword改为锁记录空间的指针,当线程2通过cas操作失败时,则先自旋一段时间。若通过多次自旋依然失败,则锁升级为重量级锁。

至于重量级锁,我觉得就是类似于AQS的双向队列,有一个监视器,他有一个队列,保存需要该锁的线程。

从偏向锁,轻量级锁,自选旋,到重量级锁。其实是锁不断升级优化的过程。偏向锁适用于大部份时间只有一个线程的场景,其消耗最小。

有一点题外话记录一下:synchronized是确保了在获取锁和释放锁的时候都有内存屏障,且数据一定会从主内存中重新load或者store到主内存。

你可能感兴趣的:(java基础)