这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战
AQS
抽象的同步队列
- 大家先来看类图
- 当我们看到
state第一个想法是否会想起上一篇文章「深入理解线程池」 - 不错,AQS其实也在在维持一个变量为了呈现状态信息
state - 其实但我们深入到读各个锁的源码就可以知道
ReentrantLock中的state是维护了当前线程获取锁的可重入次数- 而
ReentrantReadWriteLock的state的高16位是读状态,就是获取读锁的状态,低16位是写状态,就是获取写锁的状态 - 而
semaphore是表示可用信号的个数
分类!
- 其实我们要清晰的理解
state,从这个状态值去入手源码 - 我们就会发现,状态值分两种状态,分别是独占方式和共享方式
- 在共享方式下,我们都能看到一个明显的词就是
shared - 在共享方式下最重要的就是获取资源和释放资源也就是
acquireShared(int arg)``acquireSharedinterruptibly(int a)和releaseShared(int arg)
独占方式
- 独占顾名思义-就是如果一个线程获取到了资源,那么就会标记这个线程自己拿到了,其他线程再想改变state的时候,发现已经有人持有它了,那么就会失败进而堵塞
- 回头来看独占锁
ReentrantLock,它的实现就是获取锁以后,使用CAS在AQS内部将state的值改从0改为1 - 改变值以后就将当前锁的持有人设置为当前线程,在此基础上还可以设置可冲入次数
- 就是当前线程再次获取到这个锁🔐时,发现自己就是锁的持有法人,那么久将
state从1设置成2 - 上述的描述就是下面的代码
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) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
- 继续来看共享方式,其实它是与具体的线程无关的,因为在多个线程去请求资源的时候,
- 其中一个获取到以后,其他的线程还是可以获取的,但是需要CAS的方式去获取
独占方式
- 独占方式下当获取资源成功的时候便设置state的值再返回
- 获取失败就多加了 步骤,是将当前的线程封装为Node节点,类型为
Node.EXCLUSIVE,再插入到尾部 - 调用
LockSupport.park(this)挂起自己
独占-释放
- 是通过尝试
tryRelease操作,在一个线程调用release(int arg)的时候释放资源 - 其中在上面啊哦做设置state的值,调用
LockSupport.unpark(node.thread)在AQS红激活队列里面被阻塞的一个线程 - 被激活的线程使用
tryAcquire尝试,查看state是否满足,满足则被激活,否则继续在AQS队列中挂起
共享方式下就留给大家自己去看啦,思想与独占方式一样的