synchronize锁升级

本文介绍了Java中synchronized关键字在不同JDK版本下的优化过程,包括JDK1.6之前的互斥量实现,JDK1.6后的偏向锁和轻量级锁,以及JDK1.9后的锁消除和锁膨胀。着重讲解了锁升级策略,包括从偏向锁到轻量级锁再到重量级锁的转变过程。
摘要由CSDN通过智能技术生成

不同jdk版本synchronize的优化过程

Java中的synchronized关键字用于实现线程同步,保证多个线程对共享资源的操作具有原子性和可见性。在不同的JDK版本中,对synchronized的优化过程可能有所不同。以下是一般情况下的优化过程:

JDK 1.6及以前:
在旧版本的JDK中,synchronized关键字的底层实现是依赖于操作系统的底层互斥量(mutex)来实现的。每次进入synchronized块时,会使用操作系统提供的互斥量进行加锁和解锁。这种方式在竞争不激烈的情况下效率较高,但在高并发场景下可能存在性能问题

JDK 1.6及以后:
从JDK 1.6开始,Java引入了偏向锁轻量级锁来优化synchronized的性能。当一个线程进入synchronized块时,会尝试获取偏向锁,如果成功获取到偏向锁,则无需进行互斥量的加锁和解锁操作,直接执行同步操作。偏向锁的目的是优化无竞争情况下的同步操作

如果偏向锁获取失败(例如有其他线程竞争资源),则会升级为轻量级锁。轻量级锁使用CAS(Compare and Swap)操作来实现加锁和解锁,避免了系统调用和线程阻塞的开销,提高了并发性能。当竞争激烈时,轻量级锁可能会升级为重量级锁

JDK 1.9及以后:
在JDK 1.9中,Java引入了一种新的锁优化机制,即锁消除(Lock Elimination)和锁膨胀(Lock Coarsening)。锁消除是指在编译过程中,通过分析数据流和逃逸分析等技术,判断某些锁是不必要的,可以被消除掉,从而减少锁的竞争。锁膨胀是指在运行时,根据锁的使用情况,动态地将轻量级锁升级为重量级锁,以减少由于竞争导致的性能下降。

需要注意的是,以上是一般情况下synchronized的优化过程,具体优化策略可能会受到不同JDK版本和虚拟机实现的影响。优化过程的具体细节可能会有所不同。

锁升级的目的是为了在并发场景下尽量减少锁的开销,提高程序的性能。JVM会根据多线程的竞争情况自动进行锁升级,选择适当的锁级别。锁升级是JVM内部的实现细节,开发者一般无需显式操作。

锁升级的过程

问:

synchronized锁升级的详细过程讲解一下

答:

在Java中,synchronized 的锁升级过程涉及三个级别:偏向锁轻量级锁重量级锁。下面详细讲解每个级别的过程,并提供具体示例来说明:

  1. 偏向锁(Biased Locking):

    • 当只有一个线程访问同步块时,JVM会偏向于该线程,将对象的锁偏向给该线程。
    • JVM会在对象头部设置一个标识来标记偏向锁的状态。
    • 当其他线程尝试访问同步块时,会检查对象头部的偏向锁标识,如果标识为偏向锁且持有锁的线程是当前线程,则无需竞争锁。
    • 如果其他线程尝试访问同步块的线程不是当前线程,偏向锁会升级为轻量级锁
  2. 轻量级锁(Lightweight Locking):

    • 当多个线程竞争同一个锁时,JVM会尝试将锁升级为轻量级锁。
    • JVM会在对象头部存储一些信息,如指向锁记录(Lock Record)的指针。
    • 当线程尝试获取锁时,JVM使用CAS(Compare and Swap)操作尝试将对象头中的标识替换为指向自己的锁记录。
    • 如果CAS操作成功,线程获取到锁,继续执行同步块;否则,表示锁已被其他线程占用,锁升级为重量级锁。
  3. 重量级锁(Heavyweight Locking):

    • 当轻量级锁的CAS操作失败时,JVM会将锁升级为重量级锁。
    • JVM会使用操作系统提供的互斥量(Mutex)来实现重量级锁,确保同一时间只有一个线程能够获取锁。
    • 其他线程需要等待持有锁的线程释放锁后才能继续竞争锁。

问: 

如果这个锁被某个线程升级为重量级锁,并执行完毕了,那么其他线程再来获取这个锁的话,是偏向锁还是重量级锁

答:

一旦锁升级为重量级锁,并被某个线程持有后,在该线程释放锁之后,其他线程再来获取这个锁时,会尝试使用偏向锁进行优化。

重量级锁释放后,锁的状态会回到无锁状态,此时其他线程再次尝试获取锁时,JVM会尝试将锁恢复为偏向锁状态。如果发现其他线程在竞争锁,那么偏向锁会自动撤销,锁级别会升级为轻量级锁或重量级锁,具体根据竞争情况和锁升级策略来决定。

因此,一旦重量级锁被释放,其他线程再来获取该锁时,会尝试将锁恢复为偏向锁状态,然后根据实际竞争情况进行进一步的升级。

问:

 但是我在看博客的时候,看到有人说锁一旦升级,是不能降级的,感觉跟上面的解释是互斥的,哪个说法才是正确的?

答:

事实上,一旦锁升级为重量级锁,是不能再降级回偏向锁或轻量级锁的。锁的升级是单向的,一旦升级到更高级别的锁,不能再回退到低级别的锁。

当一个锁升级为重量级锁后,其他线程再来尝试获取该锁时,会直接进行重量级锁的竞争,而不会再尝试降级为偏向锁或轻量级锁。这是由于重量级锁的实现机制决定的,它使用操作系统提供的互斥量来实现同步和互斥。

因此,正确的说法是,一旦锁升级为重量级锁,是不能再降级为偏向锁或轻量级锁的。

问: 

 锁的升级是单向的,一旦升级到更高级别的锁,不能再回退到低级别的锁。 和 重量级锁释放后,锁的状态会回到无锁状态,此时其他线程再次尝试获取锁时,JVM会尝试将锁恢复为偏向锁状态。这两种说法好像是矛盾的,怎么解释?

答:

在Java中,锁的升级确实是单向的,一旦升级到更高级别的锁,无法回退到低级别的锁。

具体来说:

  1. 当锁升级到重量级锁后,是无法再回退为偏向锁或轻量级锁的。重量级锁使用操作系统提供的互斥量来实现同步,这种实现机制不支持锁的降级。

  2. 当重量级锁释放后,锁的状态会回到无锁状态,而不是恢复为偏向锁状态。其他线程再次尝试获取锁时,并不是将锁恢复为偏向锁状态。而是根据竞争情况,线程会尝试使用偏向锁或轻量级锁进行优化,而不是直接使用重量级锁。

因此,正确的解释是锁的升级是单向的,一旦升级到更高级别的锁,无法回退到低级别的锁。重量级锁释放后,锁的状态会回到无锁状态,其他线程再次尝试获取锁时,会根据竞争情况和JVM的锁升级策略来决定使用哪种级别的锁。这样解释是不是更加清晰了。

问:

synchronized有了锁升级后,还是悲观锁吗?

答:

在Java中,synchronized 使用的是一种悲观锁(Pessimistic Locking)策略。悲观锁是一种保守的机制,在访问共享资源之前,假设会发生并发冲突,因此在进入临界区之前会先获取锁,确保只有一个线程能够执行临界区代码

锁升级是指在低级别的锁(如偏向锁、轻量级锁)无法满足并发情况下的性能要求时,JVM会将锁升级为更高级别的锁(如重量级锁)。这种升级并不改变synchronized的悲观锁特性,而是优化了锁的实现方式。

无论是偏向锁、轻量级锁还是重量级锁,synchronized 都遵循悲观锁的策略,即假设会有并发冲突,并采取相应的控制措施。这种悲观的策略会带来一定的性能开销,特别是在高并发情况下。

相比之下,乐观锁(Optimistic Locking)是一种更为乐观的机制,它假设并发冲突的概率较低,不主动加锁,而是在更新时检查数据是否发生了变化。乐观锁通常使用版本号(Versioning)或时间戳(Timestamping)等机制来判断数据是否被修改。

需要注意的是,synchronized 是Java中最基本和常用的锁机制,而锁升级是底层JVM的实现细节,对于开发者来说是透明的。因此,在使用synchronized时,无需显式关注锁升级的细节,只需注意使用合适的同步范围和锁粒度,以及遵循悲观锁的特性。

菜鸟学习笔记,不对请指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值