tryLock JDK实现:
Synchronized 和Lock 对比:
读写锁:
AQS:
https://blog.csdn.net/mulinsen77/article/details/84583716
关于AQS的概念这篇文章写的挺好的,可参考,本文主要是源码的阅读。
AQS 继承AbstractOwnableSynchronizer,在AbstractOwnableSynchronizer中有exclusiveOwnerThread这个变量用于记录独占锁属于哪个线程。
- 加锁
- 尝试加锁
- 解锁:
- 尝试解锁:
AQS 加锁和解锁的实现,但是没有实现尝试加锁和尝试解锁的方法。这里使用了模板模式,尝试加锁和尝试解锁的方法需要到子类中去实现。
以ReentrantLock为例子:
公平锁和非公平锁的的抢锁的区别在于!hasQueuedPredecessors()
这里做了是否插队cas抢锁。具体看他的实现:
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
请注意,这里返回的是否有前置任务。
请注意,这里返回的是否有前置任务。
请注意,这里返回的是否有前置任务。
非公平锁直接去抢锁,而公平锁去判断是否有前置任务,只有没有前置任务(也就是当前现在公平排队时时排到自己了)才去抢锁。
JDK这里的写法保证了性能,但是阅读起来有点难。(以后注意&& 和|| 使用时不仅仅是用于判断,还可以使用!& 和 || 直接 决定是否运行后部分的是否运行。这种写法阅读性较差。)
ReentrantReadWriteLock的公平机制:
ReentrantReadWriteLock
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // writers can always barge
}
final boolean readerShouldBlock() {
/* As a heuristic to avoid indefinite writer starvation,
* block if the thread that momentarily appears to be head
* of queue, if one exists, is a waiting writer. This is
* only a probabilistic effect since a new reader will not
* block if there is a waiting writer behind other enabled
* readers that have not yet drained from the queue.
*/
return apparentlyFirstQueuedIsExclusive();
}
}
这里两个类定义了是否进行排队的判断。
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. If read count nonzero or write count nonzero
* and owner is a different thread, fail.
* 2. If count would saturate, fail. (This can only
* happen if count is already nonzero.)
* 3. Otherwise, this thread is eligible for lock if
* it is either a reentrant acquire or
* queue policy allows it. If so, update state
* and set owner.
*/
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
这里关键的就是writerShouldBlock()
这里做了是否实现公平锁。和ReentrantLock 的判断类似,writerShouldBlock
返回false 直接走后部分代码,也就是插队抢锁(非公平)。返回ture 直接 尝试抢锁失败,
PS — JDK这里使用了模板模式,代码阅读难度大。