天天看点

面试官问我:你知道synchronized锁升级吗?

作者:KerasQY

#头条创作挑战赛#

在Java中,synchronized是一种非常重要的锁机制,它用于控制多个线程之间的访问和修改共享资源的行为。但是,在高并发的环境下,使用synchronized锁可能会导致性能瓶颈和争用问题。因此,Java中的synchronized锁已经进行了多次升级和优化,以提高其效率和可靠性。面试过程中经常被面试官问到:synchronized锁升级过程。本文将介绍Java中synchronized锁的升级历程和相关的优化技术。

一、synchronized锁

在Java中,synchronized是一种关键字,它可以用于修饰方法或代码块,以实现线程之间的同步和互斥访问。synchronized锁的作用是防止多个线程同时访问和修改共享资源,从而保证程序的正确性和可靠性。下面是synchronized锁的基本使用方法和示例代码:

  1. 修饰方法

synchronized修饰的方法表示该方法是同步方法,只有一个线程可以进入该方法,其他线程需要等待。例如:

public synchronized void doSomething(){
    // do something
}           
  1. 修饰代码块

synchronized修饰的代码块表示该代码块是同步块,只有一个线程可以进入该代码块,其他线程需要等待。例如:

public void doSomething(){
    synchronized (this) {
        // do something
    }
}           

二、synchronized锁的问题和优化

虽然synchronized锁可以有效地保护共享资源的访问和修改,但在高并发的情况下,synchronized锁也存在一些问题和性能瓶颈:

  1. 争用问题

当多个线程同时请求一个synchronized锁时,只有一个线程可以成功获取锁,其他线程需要等待。如果等待的线程很多,就会导致争用问题,从而降低程序的性能和响应速度。

  1. 性能瓶颈

synchronized锁是一种独占锁,当一个线程持有锁时,其他线程必须等待。这种机制可能会导致性能瓶颈,尤其是在高并发的情况下。

为了解决这些问题,Java中的synchronized锁已经进行了多次升级和优化。下面将逐一介绍这些升级和优化。

三、synchronized锁的升级历程

  1. 偏向锁

在Java 6中,引入了偏向锁机制,在Java 6中,引入了偏向锁机制,它是synchronized锁的第一次升级。偏向锁的作用是为了减少无竞争情况下的同步操作。偏向锁的思想是,如果一个线程获得了锁,那么在未释放锁之前,这个线程再次请求锁时可以直接获得锁,而不需要再次竞争。这种机制可以减少竞争的次数,从而提高程序的性能和响应速度。

偏向锁的实现原理是在对象头中添加一个偏向锁标志位和一个线程ID,表示当前对象是否处于偏向锁状态和持有偏向锁的线程ID。当一个线程请求锁时,如果该对象的偏向锁标志位为true,并且持有偏向锁的线程ID等于当前线程的ID,那么该线程可以直接获取锁,否则需要进行竞争。偏向锁的优点是减少了无竞争情况下的同步操作,但是当多个线程竞争同一个锁时,偏向锁机制的效果就会下降。

  1. 轻量级锁

在Java 6之后,synchronized锁进行了第二次升级,引入了轻量级锁机制。轻量级锁的作用是在无竞争的情况下,使用CAS操作(Compare and Swap)来进行锁的获取和释放,避免了系统调用和线程阻塞。轻量级锁的实现原理是,在对象头中添加一个标志位,表示当前对象是否处于轻量级锁状态。当一个线程请求锁时,如果当前对象没有被锁定,并且没有竞争者,那么该线程可以通过CAS操作将对象头中的标志位设置为轻量级锁状态,并将线程ID保存在对象头中,表示该线程持有轻量级锁。当该线程释放锁时,通过CAS操作将对象头中的标志位设置回原来的状态,如果成功,表示该对象的轻量级锁状态已被释放,否则需要使用传统的synchronized锁来释放锁。

轻量级锁的优点是在无竞争情况下,使用CAS操作来进行锁的获取和释放,避免了系统调用和线程阻塞,从而提高了程序的性能和响应速度。但是,轻量级锁的缺点是在有竞争的情况下,需要使用传统的synchronized锁来进行竞争和阻塞,从而降低了程序的性能。

  1. 重量级锁

在Java 6之后,synchronized锁进行了第三次升级,引入了重量级锁机制。重量级锁的作用是在有竞争的情况下,使用操作系统的互斥量来进行锁的获取和释放,保证了多个线程之间的互斥访问。重量级锁的实现原理是,在对象头中添加一个指针,指向一个等待队列,表示当前对象被锁定并有竞争者,需要进入等待队列排队等待获取锁。当一个线程请求锁时,如果当前对象已被锁定并且有竞争者,那么该线程需要进入等待队列排队等待获取锁。当锁的持有者释放锁时,需要将等待队列中的第一个线程唤醒,并将锁转移到该线程。

重量级锁的优点是保证了多个线程之间的互斥访问,避免了数据竞争和并发安全问题。但是,重量级锁的缺点是在有竞争的情况下,需要使用操作系统的互斥量来进行锁的获取和释放,需要进行线程阻塞和切换,从而降低了程序的性能和响应速度。

四:总结

总的来说,synchronized锁的升级机制是为了提高程序的性能和响应速度,在不同的场景下选择不同的锁机制。在无竞争的情况下,可以使用偏向锁和轻量级锁来进行锁的获取和释放,避免了系统调用和线程阻塞。在有竞争的情况下,需要使用重量级锁来保证多个线程之间的互斥访问,避免了数据竞争和并发安全问题。在实际应用中,需要根据具体的业务场景和程序需求选择不同的锁机制,从而提高程序的性能和稳定性。

除了synchronized锁的升级机制外,Java还提供了一些其他的锁机制,如ReentrantLock、StampedLock、ReadWriteLock等,它们具有更加灵活和高效的特性,适用于不同的并发场景和业务需求。详情见之前的文章。

继续阅读