1.ReentrantLock的骨架
由ReentrantLock的目录结构可知,ReentrantLock有三个内部类,Sync,FairSync,NonfairSync。
其中FairSync,NonfairSync继承了Sync,Sync继承了AbstractQueuedSynchronizer。
FairSync和NonfairSync也就是我们常说的公平锁和非公平锁。
公平锁和非公平锁的概念:https://blog.youkuaiyun.com/qq_35688140/article/details/100546216
故由上面可知:ReentrantLock实际上就是对AbstractQueuedSynchronizer的封装加使用。
在java中,AbstractQueuedSynchronizer是给Java工程师提供的一个控制并发的模板类。
2.核心AQS
reentrantLock中AQS代码如下:reentrantLock所有代码都是为了调用AQS而设计的。包括加锁和释放锁都是对AQS的方法的调用实现的。
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
// 非公平锁和公平锁实现lock的方式不同,所以这里设置成抽象方法
abstract void lock();
// 非公平锁获取锁的方式,公平锁改写了该方法,加入了对队列头部的线程的判断
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();//获取锁的状态,compareAndSetState回对state更新,获取锁时state=1,释放锁后state=0
if (c == 0) {
if (compareAndSetState(0, acquires)) { //核心方法,下面讲解
setExclusiveOwnerThread(current);//设置当前线程位独占锁
return true;
}
}
else if (current == getExclusiveOwnerThread()) {//c!=0,且锁已经被独占
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);//更新state值
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) {//如果最新的状态为0,
free = true;
setExclusiveOwnerThread(null);//释放独占锁
}
setState(c);//重置state为0,放置在此方法运行期间,state被修改
return free;
}
//判断锁的持有者是否是当前线程独有
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// 获取锁的持有者
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
//获取所的状态
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
由上面的代码可以看出最核心的方法就是不断地compareAndSetState(0, acquires)这个操作,不断的用一个原子方法修改state的值。
3.compareAndSwapInt
compareAndSetState(0, acquires)两个参数,期望值,和修改后的值。通过判断state是否是我们期望的值来保证数据没有被修改。如果没有被修改则执行操作,被修改了返回false。
经过代码跟踪发现它一直调用的是unsafe的compareAndSwapInt方法。这是unsafe这个java后门,可以操作java底层内存,修改对象,设置某个对象的偏移量等等。因此这个方法不安全,随意很容易引发一系列内存问题。java也是不推荐使用此方法的,但是很多高性能框架,入netty(可以直接向直接缓冲区中写入数据就是通过该方法。以此绕过了堆缓冲区)
4.队列
相比于非公平锁,公平锁多了的判断hasQueuedPredecessors()
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;
}
跟踪代码:发现AbstractQueuedSynchronizer一直在维护一个队列,公平锁会判断执行的该线程是否在队列的头部。
5.condition
reentrantLock维持了不同的condition,不同condition上的线程是互不影响
跟进源码:我们发现每个condition维持一个队列,因为condition是一个局部变量,所以不同线程之间互不影响。如果await和signal就进行一个入队出队的操作即可。
await
signal