锁的四种状态
Java锁的四种状态就是Synchronized的升级过程
- 刚new出来没有锁的状态
- 偏向锁
- 轻量级锁
- 重量级锁
刚new出来没有锁的状态
也有人称为无锁状态,但是要慎用。
无锁原来的意思是没有重量级锁,偏向锁,CAS都被称为无锁。其实都是概念上的问题,没必要纠结。
新new出来的对象布局,可看 Java对象布局 这篇文章
偏向锁
偏向锁严格来说不是一种锁。
不存在所竞争的过程,当第一个线程来了,这把锁就属于这个线程的,在这个线程持有这把锁的时候,有另一个线程来了,就会产生锁竞争的关系,于是就是进行锁升级,升级为轻量级锁,CAS。
为什么要有偏向锁?
如果一段代码百分七八十的时间都是一个线程在请求,每一次请求都会经过锁竞争的过程,这样会降低效率。如果有了偏向锁,就会减少锁竞争,可以提高效率。如果一旦出现了锁竞争,就会进行锁升级。
轻量级锁
偏向锁考虑的是有同步无竞争时程序的效率,而轻量级锁考虑的是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。
什么时候偏向锁升级为轻量级锁?
当发生了锁竞争的时候,偏向锁就会升级为轻量级锁。
重量级锁
竞争锁的线程太多,就会被进入队列里,升级为重量级锁。
什么时候轻量级锁升级为重量级锁?
- 判断循环次数。
- 判断竞争锁的线程数。
锁对比
锁升级过程
Java中的锁有多种类型,主要包括无锁、偏向锁、轻量级锁和重量级锁。这些锁的升级过程如下:
-
无锁状态(Unlocked):当一个线程访问一个没有被锁定的对象时,它处于无锁状态。
-
偏向锁状态(Biased Locking):当一个线程获得了一个对象的锁,并且在后续的执行过程中没有其他线程竞争这个锁时,该锁会升级为偏向锁。偏向锁的目的是消除无竞争情况下的同步操作,提高性能。
-
轻量级锁状态(Lightweight Locking):如果一个线程尝试获取一个偏向锁失败,那么它会通过CAS(Compare and Swap)操作将对象头中的Mark Word 字段替换为指向锁记录的指针,并将锁记录的Owner字段设为当前线程ID。此时,该锁就升级为轻量级锁。轻量级锁使用自旋锁的形式,避免线程的上下文切换,提高性能。
-
重量级锁状态(Heavyweight Locking):轻量级锁升级为重量级锁是因为自旋操作未能成功。在多线程竞争激烈的情况下,为了保证数据的一致性和避免资源的浪费,JVM会将轻量级锁升级为重量级锁。重量级锁会让其他线程进入阻塞状态,并且使用操作系统的信号量机制来实现锁的互斥。
需要注意的是,锁的升级过程是动态的,根据竞争情况和线程执行的状态进行相应的调整。这种锁的升级过程可以提高并发性能,在无竞争情况下减少不必要的同步开销,但在竞争激烈的情况下可能会影响性能。因此,在使用锁时需要根据具体场景和需求合理选择适当的锁类型。
参考文章
- https://www.cnblogs.com/mingyueyy/p/13054296.html
- https://www.cnblogs.com/wzj4858/p/8215369.html