Synchronized锁升级的过程
Synchronized锁升级的过程
首先是偏向锁,该锁是偏向某一个线程,在加锁时如果发现只有一个线程在竞争锁,该锁会直接偏向该线程。并在线程栈中创建一个LR(锁记录),并将markword拷贝到LR中。同时锁中(或者说被加锁对象)的markword中的指针也会指向加锁线程栈中的LR。
因为Synchronized是可重入锁,所以说LR可以用来表示加了几次锁,每当解锁时,就从线程栈中弹出一个LR。
如果有多个线程同时竞争锁时,就会将锁升级为轻量级锁(自旋锁)。
当一个线程加偏向锁成功时,另一个线程过来抢占锁发现已被占用,此时这把偏向锁会被撤销,然后两个线程通过自旋 + CAS的方式抢占锁,谁抢到就将markword的锁记录指向对应线程的LR,代表该线程获得锁,另一个线程会一直自旋,当自旋到一定次数后,就会将该锁升级为重量级锁。
对于重量级锁,早期加锁以及释放锁的过程需要用户态与内核态的切换。因为它需要向系统申请锁,申请成功后还需要将这把锁从内核态返回给用户态。
原因:JVM中synchronized重量级锁的底层原理monitorenter和monitorexit字节码依赖于底层的操作系统的Mutex Lock来实现的。
用户态只能执行用户可以访问的指令,而内核态可以执行操作系统所有的指令。
当重量级锁抢占成功后,markword里记录的不再是一个线程栈内的LR,而是指向一个C++对象的ObjectMonitor。没有抢到锁的线程会被放入一个队列当中,持有锁的线程执行完毕后会唤醒队列中的线程去竞争锁。这个队列中的线程都处于阻塞状态,且是操作系统层面的阻塞。