AQS系列之Semaphore
2021-05-09 17:52:14 0 举报
JUC开发工具类
作者其他创作
大纲/内容
semaphore.acquire()
t == null
线程1
int next = current + releases;
sync.releaseShared(1)
tail结点
刚开始的时候队列没有形成 此时队列为空 创建一个空的标志结点作为head结点 并将tail也指向它
p == head
形成闭环
FairSync公平同步队列
true 创建一个空的头节点
false 重试
初始化完之后
继承
Semaphore同步队列
尝试加锁
进入addWaiter方法
线程4入队了要
pre
false 自旋
进入方法 将当前node节点设为头结点
加锁后的剩余次数是否大于等于0
thread = 线程4
被唤醒 再一次走加锁逻辑
稍后分析
setHead(node)
pre=t
state=0
aqs队列
cas 自旋
thread = null
将当前节点封装成node放入队尾
int ws = node.waitStatus; //小于0 也就是前面设置的SIGNAL节点
0:状态为初始值
next=null
一个空节点
线程2
next=t1
CONDITION:条件队列
next=t3
head结点
final Node node = addWaiter(Node.SHARED); //此方法用于将当前线程加入到等待队列的队尾 并返回当前线程所在的结点
AQS队列
就是插入队列中的最后一个元素,返回的是当前线程的节点
CANCELLED:已被取消
LockSupport.unpark(s.thread); //唤醒
state=2
实例结合源码分析流程
pre=null
pre=t2
t2节点
waitstatus=-1
唤醒后续等待线程 因为是共享资源的
thread = 线程6
/** * 业务场景 : * * 1、停车场容纳总停车量10。 * * 2、当一辆车进入停车场后,显示牌的剩余车位数响应的减1. * * 3、每有一辆车驶出停车场后,显示牌的剩余车位数响应的加1。 * * 4、停车场剩余车位不足时,车辆只能在外面等待。 */public class TestCar { //停车场同时容纳的车辆10 private static Semaphore semaphore = new Semaphore(10); public static void main(String[] args) { //模拟100辆车进入停车场 for (int i = 0; i < 10; i++) { Thread thread = new Thread(new Runnable() { public void run() { try { System.out.println(\"====\" + Thread.currentThread().getName() + \"来到停车场\"); if (semaphore.availablePermits() == 0) { System.out.println(\"车位不足,请耐心等待\"); } semaphore.acquire();//获取令牌尝试进入停车场 System.out.println(Thread.currentThread().getName() + \"成功进入停车场\"); Thread.sleep(new Random().nextInt(10000));//模拟车辆在停车场停留的时间 System.out.println(Thread.currentThread().getName() + \"驶出停车场\
unparkSuccessor(h);//唤醒后继 //唤醒h.nex节点线程
SIGNAL:等待被唤醒
线程3
true 解锁成功
NonfairSync非公平同步队列
enq(node);
r>=0
为true 加锁失败 将当前线程入队列
tail=null
结束
加锁之后的剩余次数是否小于0
tryAcquireShared(arg)
private static Semaphore semaphore = new Semaphore(10);
true 阻塞线程
进入方法
false 获取当前可加锁次数
进入FairSync的hasQueuedPredecessors()
t3节点
唤醒
int available = getState();
doReleaseShared();
1、线程会尝试释放一个令牌,释放令牌的过程也就是把同步队列的state修改为state=state+1的过程2、释放令牌成功之后,同时会唤醒同步队列的所有阻塞节共享节点线程3、被唤醒的节点会重新尝试去修改state=state-1 的操作,如果state>=0则获取令牌成功,否则重新进入阻塞队列,挂起线程。
parkAndCheckInterrupt()
得到加锁之后的剩余次数
t1节点
加入同步队列
remaining < 0
Semaphore类
head=null
t节点
CAS 什么时候为true 什么时候为false 源码是什么样子的???????
队列中是否还有其他线程
false 替换node节点状态 cas
semaphore.acquire();//获取令牌尝试进入停车场
释放锁
false 加锁失败
True
获取锁
当前剩余加锁次数 + 解锁次数
next
next=t2
compareAndSetHead(new Node())
1、当调用new Semaphore(10) 方法时,默认会创建一个非公平的锁的同步阻塞队列。2、把初始令牌数量赋值给同步队列的state状态,state的值就代表当前所剩余的令牌数量。
当前节点是否为头结点
进入FairSync中的tryReleaseShared方法
判断线程是否可阻塞(waitStatus==SINGAL) 不可则更改node节点状态为SINGAL
sync.acquireSharedInterruptibly(1);// 共享模式下获取令牌
release()
当资源竞争完之后 那么后来的线程就要入同步队列了 此时有一个特例操作就是 队列为空时 执行addWaiter方法
state=10
int remaining = available - acquires;
false CAS修改可加锁次数
state=1
pre=t1
state = 0
doAcquireSharedInterruptibly(arg);
此时假设有2个资源可以共享 那么经过tryAcquireShared(arg)这一函数操作之后 有三个线程获取到了资源 此时AQS此时初始化节点是什么样子的呢
Sync 抽象同步器(一个内部类)
int current = getState();
false将新节点放入队尾
thread = 线程5
node节点
tryReleaseShared(arg)
final Node p = node.predecessor(); //获得当前节点pre节点
int r = tryAcquireShared(arg);
true 加锁成功
AQS 队列
AQS 抽象队列同步器
就是试探性的看看有没有节点释放资源 免得插入AQS 浪费时间
semaphore.release();//释放令牌,腾出停车场车位
CAS恢复可加锁次数
true尝试加锁
0 条评论
下一页