ReentrantLock的条件变量await+signal+公平锁原理

目录

 公平锁实现原理:

条件变量-await

条件变量之唤醒-signal


 

 公平锁实现原理:

它会判断你的AQS队列中是否有前驱节点,没有才会去竞争;

判断方法hasQueuedPredecessors():1.根节点head后是否有第二个节点 2.拥有者是否是当前线程;

条件变量-await

 public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }

1.Node node = addConditionWaiter();先进入addConditionWaiter()——>目的:将线程放入Condition队列中,将线程封装成一个Node节点(关联线程,加入条件等待队列);

 

    private Node addConditionWaiter() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node t = lastWaiter;
            // If lastWaiter is cancelled, clean out.
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
          //创建一个新的Node,关联线程,状态为-2
            Node node = new Node(Node.CONDITION);
          
          //如果Condition队列首节点firstWaiter为null,就将节点设置为头节点,若不为null,就设置为Condition队列中最后一个节点;
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }

2.int savedState = fullyRelease(node);目的->因为线程其实是拿到锁资源的,只是因为我加了条件变量,如果不满足就触发await方法;

既然拿了锁资源,还要将其阻塞,那么我们肯定是要将它的state重置;

而fullyRelease:

就是一次释放,令state为-1;

 final int fullyRelease(Node node) {
        try {
            int savedState = getState();
       //释放节点,混淆头节点的下一个节点
            if (release(savedState))
                return savedState;
            throw new IllegalMonitorStateException();
        } catch (Throwable t) {
            node.waitStatus = Node.CANCELLED;
            throw t;
        }
    }

release中的unparkSuccessor(Node node)会唤醒下一个节点; 

 public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }


条件变量之唤醒-signal

     public final void signal() {
//先判断是不是锁的持有者
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
//找到条件变量队列中的第一个元素
            Node first = firstWaiter;
            if (first != null)
//队首不为null调用doSignal
                doSignal(first);
        }

 唤醒的话,我们可以知道doSignal的目的就是将条件变量队列中的节点断开,然后放到竞争队列中(等待队列中)

1.第一个firstWaiter往后走一个并指向null ,最后一个也指向null;

2.transferForSignal:将节点放到AQS队列尾部,节点的waitStatis改为0,它的前一个节点为-1;

   private void doSignal(Node first) {
            do {
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }

transferForSignal:目的就是将Condition队列中的节点状态修改为0,然后加入等待队列中尾部,并且修改它的前驱节点状态,让前驱节点唤醒它,核心也就是unpark;

final boolean transferForSignal(Node node) {
      //进行CAS操作,将当前节点waitStatus设置为0;
        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
            return false;

      //将节点加入等待队列中,尾部,成功的话就会返回它的前驱节点
        Node p = enq(node);
      //检查当前节点前驱节点的状态:目的是将状态改为-1 (占位作用,去唤醒下一个元素,也就是我们这个节点)
        int ws = p.waitStatus;

      //修改前驱节点的状态
        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
         //底层还是unpark唤醒
            LockSupport.unpark(node.thread);
        return true;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fairy要carry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值