目录
本文主要从源码的角度分析下java中的Lock锁以及他的底层依赖AQS,在多线程编程中我们一定会用到锁,java提供了JUC包来更好的并发编程,,关于JUC包的介绍可以参看之前的文章。
主要分为一下几个部分:
1.ReentrantLock 锁的特点,
2.ReentrantLock核心代码讲解
3.AQS 的核心代码讲解
ReentrantLock 锁的特点
ReentrantLock是Lock接口的具体实现,lock锁相对于synchronized是轻量级锁,是api级别的,synchronized是JVM级别的,Lock的具体特点如下:
1)使用方面需要显示的获取锁,并需要主动释放锁。
2)可中断,可重入。
3)支持公平锁和非公平锁。
ReentrantLock核心代码讲解
总体介绍:这里只简单的介绍基本的构造函数、核心变量和核心方法,不会把所有代码和方法列出。
1)核心变量:有一个核心内部类变量private final Sync sync,是实现了同步线程队列AQS。同时他有两个实现类NonfairSync(非公平锁)和FairSync(公平锁)。
Sync类源码:
NonfairSync(非公平锁)源码)
FairSync(公平锁)
2)构造函数:ReentrantLock有两个构造函数,一个无惨构造函数ReentrantLock(),默认是非公平锁实现,一个有参构造函数ReentrantLock(boolean fair),参数fair代表的是否是公平锁。一般情况下非公平锁要比公平锁效率高,因为减少了队列中唤醒线程时的线程切换,所以默认是非公平锁。
3)核心方法:
获取锁的方法:lock()、tryLock()和tryLock(long timeout, TimeUnit unit)三个方法
,lock()是调用的sync.lock(),也就是根据ReentrantLock对象是公平锁还是非公平锁来获取锁,tryLock直接是非公平锁逻辑,调的是sync的nonfairTryAcquire()方法,而tryLock(long timeout, TimeUnit unit)是在超时间内获取到锁返回true,否则是false,它获取的是公平还是非公平锁也是由ReentrantLock具体对象决定。
释放锁的方法:unlock(),他直接调用的sync.release(1)。
获取线程同步条件对象:newCondition()方法是返回一个Condition对象,用于线程间协同通信。
AQS源码分析
AQS是 AbstractQueuedSynchronizer的缩写,是一个abstract 类,通过上边ReentrantLock的分析,可以看出ReentrantLock底层就是AbstractQueuedSynchronizer,是通过Sync继承了AbstractQueuedSynchronizer,重写了获取和释放锁的具体逻辑。
那么AQS基本原理很明确,就是解决锁状态问题,解决未获取到锁的线程阻塞问题、以及多线程间的同步问题,所以AQS具体结构:
- Abstract : 是一个抽象类,因为不具体上锁,所以通过模版设计模式暴露上锁逻辑,有子类实现tryAcquire()和tryRelease()。
- Queue:线程阻塞队列,完成抢不到锁的队列排队。
- Synchronizer:同步
- CAS+state:完成多线程抢锁逻辑
AQS核心代码:
核心方法:
获取锁的方法acquire(int arg) ,具体逻辑是先通过CAS获取锁,如果成功返回成功,失败则如阻塞队列:
释放锁:release(int arg)释放锁,先判断释放锁是否成功,成功了唤醒队列里的等待线程。