JUC并发包之ReentrantLock原理详解

我们都知道ReentrantLock主要利用CAS+AQS队列来实现。那么什么是CAS,AQS呢?

什么是AQS?

同步队列 AQS,全称 AbstractQueuedSynchronizer。就是用来同步队列的。
AQS 的功能分为两种:独占和共享。
独占锁,每次只能有一个线程持有锁,比如前面给大家演示的 ReentrantLock 就是
以独占方式实现的互斥锁
共 享 锁 , 允 许 多 个 线 程 同 时 获 取 锁 , 并 发 访 问 共 享 资 源 , 比 如读写锁ReentrantReadWriteLock。
那AQS 队列内部维护的是一个 FIFO 的双向链表。这种结构的特点是每个数据结构都有两个指针,分别指向直接的后继节点和直接前驱节点。所以双向链表可以从任意一个节点开始很方便的访问前驱和后继。每个 Node 其实是由线程封装,当线程争抢锁失败后会封装成 Node 加入到 ASQ 队列中去;当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)。

CAS 的实现原理

protected final boolean compareAndSetState(int expect, int update) {
	 // See below for intrinsics setup to support 	this
	 return unsafe.compareAndSwapInt(this, 	stateOffset, expect, update);
}

通过 cas 乐观锁的方式来做比较并替换,这段代码的意思是,如果当前内存中state 的值和预期值 expect 相等,则替换为 update。更新成功返回 true,否则返回 false.这个操作是原子的,不会出现线程安全问题,这里面涉及到Unsafe这个类的操作,以及涉及到 state 这个属性的意义。state 是 AQS 中的一个属性,它在不同的实现中所表达的含义不一样,对于重入锁的实现来说,表示一个同步状态。它有两个含义的表示

  1. 当 state=0 时,表示无锁状态
  2. 当 state>0 时,表示已经有线程获得了锁,也就是 state=1,但是因为
    ReentrantLock 允许重入,所以同一个线程多次获得同步锁的时候,state 会递增,
    比如重入 5 次,那么 state=5。而在释放锁的时候,同样需要释放 5 次直到 state=0
    其他线程才有资格获得锁。

JAVA中的CAS操作都是通过sun包下Unsafe类实现,而Unsafe类中的方法都是native方法。

CAS的缺点:
CAS虽然很高效的解决原子操作,但是CAS仍然存在三大问题。ABA问题,循环时间长开销大和只能保证一个共享变量的原子操作。

Reentrantlock的源码调用图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43978695/article/details/109276725