深入ReentrantLock

86 阅读2分钟

1 ReentrantLock和synchronized的区别

核心区别: ReentrantLock是个类,synchronized是关键字,当然都是在JVM层面实现互斥锁的方式 效率区别:

如果竞争比较激烈,推荐ReentrantLock去实现,不存在锁升级概念。而synchronized是存在 锁升级概念的,如果升级到重量级锁,是不存在锁降级的。

底层实现区别: 实现原理是不一样,ReentrantLock基于AQS实现的,synchronized是基于ObjectMonitor

功能向的区别: ReentrantLock的功能比synchronized更全面。

ReentrantLock支持公平锁和非公平锁

ReentrantLock可以指定等待锁资源的时间。

选择哪个:如果你对并发编程特别熟练,推荐使用ReentrantLock,功能更丰富。如果掌握的一般 般,使用synchronized会更好

2 AQS概述

AQS就是AbstractQueuedSynchronizer抽象类,AQS其实就是JUC包下的一个基类,JUC下的很多 内容都是基于AQS实现了部分功能,比如ReentrantLock,ThreadPoolExecutor,阻塞队列, CountDownLatch,Semaphore,CyclicBarrier等等都是基于AQS实现。 首先AQS中提供了一个由volatile修饰,并且采用CAS方式修改的int类型的state变量。 其次AQS中维护了一个双向链表,有head,有tail,并且每个节点都是Node对象

static final class Node {  
static final Node SHARED = new Node();  
static final Node EXCLUSIVE = null;  
static final int CANCELLED = 1;  
static final int SIGNAL = -1;  
static final int CONDITION = -2;  
static final int PROPAGATE = -3;  
volatile int waitStatus;  
volatile Node prev;  
volatile Node next;  
volatile Thread thread;  
}

AQS内部结构和属性

image.png

3 加锁流程源码剖析

3.1 加锁流程概述

这个是非公平锁的流程

image.png

3.2 三种加锁源码分析

lock方法

  1. 执行lock方法后,公平锁和非公平锁的执行套路不一样
// 非公平锁  
final void lock() {  
// 上来就先基于CAS的方式,尝试将state从0改为1  
if (compareAndSetState(0, 1))  
// 获取锁资源成功,会将当前线程设置到exclusiveOwnerThread属性,代表是当前线程持有着锁资源  
setExclusiveOwnerThread(Thread.currentThread());  
else  
// 执行acquire,尝试获取锁资源  
acquire(1);  
}  
// 公平锁  
final void lock() {  
// 执行acquire,尝试获取锁资源  
acquire(1);  
}
  1. acquire方法,是公平锁和非公平锁的逻辑一样
// tryAcquire:再次查看,当前线程是否可以尝试获取锁资源  
if (!tryAcquire(arg) &&  
// 没有拿到锁资源  
// addWaiter(Node.EXCLUSIVE):将当前线程封装为Node节点,插入到AQS的双向链表的结尾  
// acquireQueued:查看我是否是第一个排队的节点,如果是可以再次尝试获取锁资源,如果长时间拿不到,挂起线程  
// 如果不是第一个排队的额节点,就尝试挂起线程即可  
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))  
// 中断线程的操作  
selfInterrupt();  
}