源码分析AbstractQuenedSynchronized(二) 源码分析AbstractQuenedSynchronized(三)
文章目录
AbstractQuenedSynchronized数据结构模板方法
ReentrantLockReentrantLock获得公平锁ReentrantLock释放公平锁
公平锁和非公平锁公平锁的争锁过程非公平锁的争锁过程总结
从 ReentrantLock 的公平锁源码出发,分析AbstractQueuedSynchronizer 这个类如何工作
AbstractQuenedSynchronized
该类是一个抽象类,简称AQS,是Java并发包的基础工具类,是实现ReentrantLock、CountDownLatch、Semaphore、FutureTask等类的基础。
数据结构
双向队列,结点Node包含:pre+next+thread+waitStatus
图片来源https://javadoop.com/post/AbstractQueuedSynchronizer
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
;
Node nextWaiter
;
}
模板方法
void acquire(int arg
) ***->子类会覆写其中的
boolean tryAcquire(arg
)方法
boolean release(int arg
) ***->子类会覆写其中的
boolean tryRelease(arg
)方法
Node
addWaiter(Node mode
)
Node
enq(final Node node
)
boolean acquireQueued(final Node node
, int arg
)
boolean shouldParkAfterFailedAcquire()
boolean parkAndCheckInterrupt()
void unparkSuccessor(Node node
)
ReentrantLock
默认非公平锁,通过构造器参数中的布尔值来确定锁是否公平,通过内部类Sync来管理锁,真正的获取锁和释放锁由Sync两个实现类来实现,
public ReentrantLock() {
sync
= new NonfairSync();
}
public ReentrantLock(boolean fair
) {
sync
= fair
? new FairSync() : new NonfairSync();
}
ReentrantLock获得公平锁
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;
}
}
ReentrantLock释放公平锁
public void unlock() {
sync
.release(1);
}
公平锁和非公平锁
公平锁的争锁过程
static final class FairSync extends Sync {
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;
}
}
非公平锁的争锁过程
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(0, 1))【对比】和公平锁相比,并没有对锁的等待状态进行判断,而是直接调用一次CAS,尝试去获得锁
setExclusiveOwnerThread(Thread
.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires
) {
return nonfairTryAcquire(acquires
);
}
final boolean nonfairTryAcquire(int acquires
) {
final Thread current
= Thread
.currentThread();
int c
= getState();
if (c
== 0) {【对比】和公平锁相比,这里没有对阻塞队列进行判断,即根本不管有没有线程在等待锁
if (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;
}
}
总结
非公平锁与公平锁的lock方法有以下两点不同:
非公平锁: 进入lock方法后直接尝试CAS获得锁,成功则直接返回; 公平锁: 进入lock方法后首先要获取锁的等待状态state,判断是否有线程在等待锁(state是否为0)
非公平锁: CAS未成功后进入父类AQS的acquire方法,然后调用自己的nonfairTryAcquire方法,如果暂时没有线程持有锁或者当前锁可重入,则直接获得锁,也不会对阻塞队列有没有线程在等待锁作判断,如果没有获得锁则后续步骤和公平锁一样,将当前线程封装成结点插入到队列中自旋等待。 公平锁: 在步骤1的基础上,当锁的等待状态为0,即未有线程持有锁时,会进而判断阻塞队列中有没有线程在等待锁
对比之下,非公平锁的吞吐量更大,但是也有可能使阻塞队列中的线程长期处于饥饿状态。
参考:https://javadoop.com/post/AbstractQueuedSynchronizer