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内部结构和属性
3 加锁流程源码剖析
3.1 加锁流程概述
这个是非公平锁的流程
3.2 三种加锁源码分析
lock方法
- 执行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);
}
- acquire方法,是公平锁和非公平锁的逻辑一样
// tryAcquire:再次查看,当前线程是否可以尝试获取锁资源
if (!tryAcquire(arg) &&
// 没有拿到锁资源
// addWaiter(Node.EXCLUSIVE):将当前线程封装为Node节点,插入到AQS的双向链表的结尾
// acquireQueued:查看我是否是第一个排队的节点,如果是可以再次尝试获取锁资源,如果长时间拿不到,挂起线程
// 如果不是第一个排队的额节点,就尝试挂起线程即可
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 中断线程的操作
selfInterrupt();
}