类介绍
类继承关系
1.pngReentrantLock
实现了Lock
接口和Serializable
接口。
类介绍
可重入互斥锁,此锁依赖AQS
实现了最基本的互斥锁,提供了线程在占有锁的情况下可重复获得锁的功能。
此对象的实现思路很简单,提供了一个对象继承AQS
,对线程的操作全部转化为直接或者间接对AQS
的方法的依赖。
注意
ReentrantLock
提供了两种获得锁的方法,一种是不公平的,一种是相对公平的。
公平的那个不保证一定公平。这个我们在具体介绍时会详细介绍。
遗留问题
获得/释放锁时的入参 arg
、AQS
的状态state
,在这里赋予了它特别的意义:占有锁的线程重入次数
源码
内部类
Sync
类介绍
此类是ReentrantLock
使用AQS
的基础类,此类对AQS
中ReentrantLock
需要的、公平模式和非公平模式下都要用的方法进行了实现。
方法介绍
/**
* 可重入互斥锁的同步器的基础类。定义了两个他的子类,一个是公平的、一个是非公平的
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
// 自定义 serialVersionUID ,方便代码变化后做序列化、反序列化兼容
private static final long serialVersionUID = -5179523762034025860L;
/**
* 留给子类实现的接口,根据公平/不公平实现不同
*/
abstract void lock();
/**
* 不公平模式下的 tryLock() 实现,由于在 ReentrantLock 中也直接调用了,
* 所以算是通用的方法吧,放这里
*
* 入参为获得锁的入参 arg
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 获得当前锁被它的占有线程重入的次数
int c = getState();
// 当前锁没人用,可竞争
if (c == 0) {
// 用CAS来竞争,竞争到就占用成功
// 没竞争到就算了
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 当前锁被占用,看看是不是被自己占用的
else if (current == getExclusiveOwnerThread()) {
// 自己占用的,重入!
int nextc = c + acquires;
// 如果溢出了就报错,重入次数过多
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
// 这里和上面不同,这里只有自己在用,直接设置即可,上面使用 CAS 是
// 因为锁被释放,有多个线程在竞争,可能有多个线程在同时修改 state 那
// 个变量
setState(nextc);
return true;
}
return false;
}
// 互斥模式的释放都一样,不涉及公不公平的问题,所以就在这里实现了
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
// 本线程不占有锁,不能继续执行
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 释放完锁被释放了
if (c == 0) {
free = true;
// 清除对锁的占用
setExclusiveOwnerThread(null);
}
// 这里将 c 设置成0,才有人竞争,所以这里还是一个线程操作,不用 CAS
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
// 判断当前线程是否占用锁
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// 为外部类提供的方法
// 不明白为什么要这么判断一下,没必要,即使锁没有被占用返回的也是 null
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
// 当前的锁都是互斥锁,可能是怕被错误调用吧
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* 从输入流中反序列化
*
* 反序列化后将锁重置为未获取状态
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
NonfairSync
类介绍
Sync
的子类,提供不公平的等待
方法介绍
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* 非公平锁,有线程来了,先竞争一下锁,如果竞争到了,更改了锁的状态,就直接运行
*
* 失败了就走 AQS 的正经流程:
* 先尝试调用 tryAcquire 获得一下锁,失败就进队列阻塞,等待获得锁后被唤醒
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
思路提要
注意,正常的 AQS
子类中提供了两个插队的地方:
-
lock()
可以插队,有线程来了先竞争一下锁 -
AQS.acquire()
可以插队,一般都是先调用tryAcqurie()
竞争一下,失败了再乖乖进队
FairSync
类介绍
Sync
的子类,提供公平的等待。
方法介绍
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* 做判断,如果同步队列中有前驱就直接获得失败
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 锁可获得
if (c == 0) {
// 如果它在队头就开始竞争锁
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 锁已被占有,就看看能不能重入一下
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
内部方法
提供了一些方便的用于查询锁当前状态的方法,可以用来做监视器等。
这里直接把方法粘过来了,都很简单
// 获得重入次数
public int getHoldCount() {
return sync.getHoldCount();
}
// 判断是否被当前线程获得
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
// 判断锁是否被占用
public boolean isLocked() {
return sync.isLocked();
}
// 判断当前同步器是否公平
public final boolean isFair() {
return sync instanceof FairSync;
}
// 获得占用当前锁的线程
protected Thread getOwner() {
return sync.getOwner();
}
// 获得是否有竞争当前锁的线程
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
// 获得入参线程是否在竞争当前锁
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
// 获得竞争锁的队列长度
public final int getQueueLength() {
return sync.getQueueLength();
}
// 获得竞争锁的所有线程
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
// 判断是否有线程被 Condition 阻塞等待唤醒
// 判断条件同步队列中是否有线程
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
// 获得条件同步队列中线程个数
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
// 获得条件同步队列中的线程
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
暴露的方法
构造方法
/**
* 非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 可以公平锁
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
lock()
介绍
阻塞等待获得锁,依赖构造函数生成的Sync
源码
public void lock() {
sync.lock();
}
lockInterruptibly()
介绍
阻塞等待锁,可打断,打断抛异常
源码
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
tryLock()
介绍
尝试获得锁,非阻塞,根据返回值判断是否获得锁。
直接竞争锁,不排队,在公平模式下也可以调用
源码
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
tryLock(long timeout, TimeUnit unit)
介绍
尝试获得锁,限时、可打断,阻塞获得
返回值表示是否在超时前获得
源码
// 返回 true 表示获得锁
// 返回 false 表示超时
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
unlock()
介绍
释放本线程获得的锁【释放一次,也就是重入次数-1,减到0时释放锁】
源码
public void unlock() {
sync.release(1);
}
newCondition()
介绍
创建 Condition
对象,用来使获取锁执行一半的线程放弃锁阻塞
源码
public Condition newCondition() {
return sync.newCondition();
}
网友评论