计算机系统应用教程网站

网站首页 > 技术文章 正文

高并发面试题汇总-可重入锁ReentrantLock以及其他显式锁相关

btikc 2025-02-10 11:31:43 技术文章 10 ℃ 0 评论

可重入锁ReentrantLock实现原理与Synchronized有什么不同?

对于所有锁来说,其实现的目的都是为了能够保证让所有竞争共享资源的线程获取到一个标识,来标记出共享资源的访问操作。

在使用Synchronized的时候,是通过对象头中的魔数标识来进行标记,是通过JVM底层来实现。而ReentrantLock则是基于实现了Lock接口来实现锁操作,是通过Volatile关键字修饰了一个Int类型的变量,然后保证了每个线程对于int变量的可见性和原子性的修改,本质采用了AQS框架。

AQS到底是什么?

AQS(Abstract Queue Synchronizer)是一个用来构建锁的同步处理器框架,对于实现了Lock接口的锁来讲,基本上都是采用了这种框架机制,当然在Semaphore、CountDownLatch等都是采用AQS来构建。

在AQS内部通过Volatile关键字来修饰了一个static的变量用来表示同步的状态,当线程调用了lock方法的时候,如果状态值为0,那么表示没有其他线程占用共享资源,这个时候就可以获取到该锁,并且将状态值设置为1;如果状态值为1,则说明当前正在有其他线程操作共享变量,此时操作线程就需要进入到一个同步等待的队列。

在AQS内部,通过Node结构实现了一个双向链表的队列,来完成对于线程获取锁的排队等待队列,当有线程尝试获取锁失败之后,就会被添加到队列的尾部,等待获取锁。

在Node内部是对同步等待线程的封装,包含了线程的状态,前驱节点、后置节点等信息。其内部还有两个常量,SHARED和EXCLUSIVE,分别表示共享模式和独占模式,而所谓的共享模式和独占模式分别表示了乐观和悲观两种状态。

通过AQS的内部类ConditionObject构建等待队列,当Condition调用wait方法之后,现成会进入到等待队列,当Condition调用了signal()方法的时候,线程将从等待队列中移动到同步队列中进行锁竞争操作。

AQS和Condition各自维护的是各自的队列,在加锁或者是Condition的时候,就是对于两个队列的移动。

对比Synchronized与ReentrantLock的区别?

上面提到ReentrantLock是Lock的实现类,是一个互斥的同步锁机制,从功能的角度上来讲二者的区别主要有如下一些

  • ReentrantLock在等待中可被中断:当持有锁的线程长时间不释放锁的时候,正在等待的线程可以放弃等待,然后继续执行其他的操作。
  • ReentrantLock可以指定获取锁的超时时间:在指定时间范围内尝试获取锁,如果时间到了,依然没有获取到锁,那么就返回结果。
  • ReentrantLock可以判断是否有线程在排队等待获取锁。
  • ReentrantLock可以在响应中被中断:当获取到锁的线程被某个操作中断的时候,能够对中断操作进行处理,抛出异常,同时占用的锁也会被释放。
  • ReentrantLock可以实现公平锁机制

从锁操作的角度上来讲Synchronized是在JVM层面上实现,所以对于锁操作的控制是由JVM来控制的,如果执行代码发生了异常JVM则会自动释放锁。但是使用Lock的时候需要通过在异常finally中进行锁的释放。

从性能的角度上来看,在锁竞争不是太激烈的时候,使用Synchronized要比ReentrantLock的性能要高。而在高竞争的场景下,Synchronized是执行效率比较低的一种锁机制,与ReentrantLock相比。

ReentrantLock是如何实现重入机制的?

ReentrantLock内部实现了一个自定义的同步器Sync,这个同步器实现了AQS和AOS,AOS提供了互斥锁的持有方式。就是通过CAS算法将线程对象放入到双向链表中,并且每次获取锁的时候,看一下当前维护的线程ID是那个,和当前请求的线程ID进行比较,然后就可以实现锁的重入了。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表