c++ 队列_队列同步器(AQS)

aqs 同步队列的实现

Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();

首先: lock 加锁的时时序图

8676cc2612c64d7ffb6bb37fe190f168.png

线程A , 线程B 争抢锁, 总有一个线程能正确成功。 并将锁的次数标志 State= +1 , State标识锁的次数。

并成功释放执行 unlock() ,将 State 设置位0;

第一步:

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

compareAndSetState(0,1) 原子性操作, 会将state 的状态由0-> 1.。 即标识锁了1次。 设置成功后会当前

exclusiveOwnerThread = thread;

如果线程 b 正确 第一步失败, 则会进入 acquire(1);

第二步:

tryAcquire(int acquires) , 改方法调用 nonfairTryAcquire(int acquires),

2fd1bb2b820f4b4aba41fb0a68c728f3.png

尝试 获取锁。 如果是重入锁, 则计算 state的值。

如 图片中的138行中,当两个线程相等时。 则计算state的值。

大家都知道lock锁是可重入的, 那么怎么去计算重入锁的次数呢? 没错就是依赖state的值, lock 多少次, unlock 就要多少次

第三步, 重头戏 。 是如何构建 一个节点链表的呢? 比如线程c, 线程d进来争抢锁。 又是如何的存储的呢?

addWaiter(Node mode) : 创建节点 , 并加入队列。

48f2db17c672555757fc15c8d15a3659.png

因为还初始化时, tail 会等于空, 所以会走 616 行代码

enq(Node node)

3137044ff3e0f8909184cba9b76b4b11.png

这是一个 循环, 会有两个过程循环的流程如下:

第一次循环, 初始化head,tail 节点, 并head==tail

656eb647a2c7f390ef475a487c081a29.png

第二次循环。设置新建节点的 per, 和next 节点,返回当线程node节点, 并跳出循环

f1d16306fdb509db0beeb936b5356472.png

第四步:

acquireQueued(addWaiter(Node.EXCLUSIVE), arg),

将每一个前置节点waitStatus= -1=Signal, 并阻塞每一个线程,不释放资源

b6dd760bc5e86dbb02f86679ea1377d9.png

final Node p = node.predecessor(); 获取每个节点的前置节点。

当由于state的 state不为0, 应为锁未释放。所以走到 869 行。

shouldParkAfterFailedAcquire(Node pred, Node node):是一个无限循环, 会将p节点(node 的前置节点 ) 的 wait 0->1.

a37bc2704d0135bf6ab41f550f201962.png
parkAndCheckInterrupt()  知道阻塞在这里。LockSupport.park(this); 让当前线程阻塞。 直至LockSupport.unpark 才会释放线程

LockSupport.park(this) 不释放线程资源。

25416a953f9795c3e8b69291b952e86c.png

解锁操作:

lock.unlock();

tryRelease方法,将status的减一, 如果为0 , 将当前线程置为空:setExclusiveOwnerThread(null);

unparkSuccessor(Node node),将当前的节点修改为0,waitStatus=0;

并释放挂起的线程 LockSupport.unpark(s.thread);

f7ebf3fecfea1135a3f3e3c83e01e446.png

线程停止阻塞后, 便会继续执行代码。 在第四步的无限循环中。因为state=0 , 且前节点时=head时, 会释放前节点。

b7a9546eb13b4425dd0fcba23b95a193.png

则当前节点会置为新的head 节点。 原head 节点则会被 Gc 垃圾回收。

线程C 以此类推

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值