JDK中有以下基于AQS的实现
ReentrantLock
CountDownLatch
Semaphore
ReentrantReadWriteLock
CyclicBarrier (委托给ReentrantLock)
首先关于源码中经常出现 final ReentrantLock takeLock = this.takeLock 写法:
这是一个有关volatile变量的lock-free的典型习惯编码。在第一行第一次到读到变量后,另一个线程会更新这个值,但你只对初始读到的值感兴趣。
另外,即使我们讨论的成员变量不是 volatile而是final, 这个习惯用法也与CPU缓存有关:从栈读变量比从堆读变量会更cache-friendly,本地变量最终绑定到CPU寄存器的可能性更高。
ReentrantLock的独占和共享:
基本上一致,区别:
非公平锁是:
先state+1,然后直接得到锁,
而公平锁则是:
先尝试去获取锁,如果得到了锁则state+1.
实现公平性的关键在于:如果锁被占用且当前线程不是持有者也不是等待队列的第一个,则进入等待队列。
可见是否公平实际上是对处于等待队列中的线程来说的。
ReentrantLock都是把具体实现委托给内部类
而不是直接继承自AbstractQueuedSynchronizer,
这样的好处是用户不会看到不需要的方法,
也避免了用户错误地使用AbstractQueuedSynchronizer的公开方法而导致错误。
// 非公平获取
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)
// 溢出。加锁次数从0开始,加锁与释放操作是对称的,
// 所以绝不会是小于0值,小于0只能是溢出。
throw new Error("Maximum lock count exceeded");
// 锁被持有的情况下,只有持有者才能更新锁保护的资源,
// 所以这里不需要用CAS。
setState(nextc);
return true ;
}
return false ;
}
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1); //acquire会首先调用tryAcquire,所以公平策略的控制留给tryAcquire。
}
// tryAcquire的公平版本。除非是递归调用或没有等待者或者是第一个,否则不授予访问。
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 ;
}
}
来源:https://blog.csdn.net/cplcdk/article/details/99291536