zoukankan      html  css  js  c++  java
  • JUC_02 AQS工作原理

    imageimageimage

    AQS: state + chl队列完成

    Lock.lock()

    判断state状态:compareAndSetState

    判断state值是否等于0,如果等于0,
    说明当前还没有线程获取锁对象资源。
    compareAndSetState(0, 1):将state值改为1,
    setExclusiveOwnerThread:将当前线程设置为排它线程,其它线程获取锁资源需要等待

    获取锁:acquire

    acquire(arg) {
    if (!tryAcquire(arg) && acquireQueued(
    addWaiter(Node.EXCLUSIVE), arg))
    selfInterrupt();
    }

    尝试获取锁:tryAcquire

    tryAcquire:
    1、判断当前state值是否为0,若是,则并把当前线程设置为排它线程并直接给当前线程放行,
    2、判断当前线程是否和排它线程是同一个线程,若是,则将state值进行累加并直接给当前线程放行

    添加等待者:addWaiter

    1、判断tail节点是否为空
    Node pred = tail;
    若不为空,则将新加入的node.prev指向pred,再将tail节点改为node节点,最后将pred.next指向node节点

    若为空,则执行enq方法(自旋)
    第一次:
    tail为空:
    创建一个新节点作为哨兵节点node
    将head节点指向node,然后将
    tail节点指向head。
    第二次:
    tail不为空:
    Node t = tail;
    将node.prev指向t,
    将tail指向node,
    最后将t.next指向node

    将当前线程封装成Node节点,判断tail节点是否为空,若为空,则指向enq方法(创建哨兵节点),若不为空,直接拼接后续节点。

    加入队列:acquireQueued

    1、先获取当前节点的前序节点:Node p = node.predecessor(),
    若p==head且tryAcquire(arg)为true时,
    将当前节点作为head节点,且p.next=null(GC回收)

    若不满足,则继续执行:shouldParkAfterFailedAcquire(p, node) &&
    parkAndCheckInterrupt()

    获取锁成功后将node节点作为head节点,head.next置为nul(GC回收)

    final Node p=node.predecessor();
    if (p == head && tryAcquire(arg)) {
    setHead(node);
    p.next = null; // help GC
    failed = false;
    return interrupted;
    }

    获取锁失败后进行阻塞操作:shouldParkAfterFailedAcquire && parkAndCheckInterrupt

    一、shouldParkAfterFailedAcquire
    1、判断Node的waitStatus状态,
    将pred节点的waitStatus设置为Node.SIGNAL对应值,用于指示线程执行unpark操作
    二、parkAndCheckInterrupt
    1、LockSupport.park(this);
    将当前线程进行阻塞

    Lock.unlock

    释放锁:release

    尝试释放锁:tryRelease

    1、判断当前线程是否是获取锁的排它线程,若不是则抛出异常:IllegalMonitorStateException
    2、判断state值是否为0,若等于0则将排它线程置为null
    3、更新state状态值

    唤醒队列中的节点:unparkSuccessor

    一、判断head节点是否为空且waitStatus值是否为0,满足条件:
    1、将该节点的waitStatus值重置为0
    2、获取下一个节点,若下一个节点s不为空,
    则执行LockSupport.unpark(s.thread);
    从此唤醒s节点的线程。让它尝试继续获取锁操作

    更改waitStatus值状态:compareAndSetWaitStatus
    唤醒阻塞线程:unpark(s.thread)
  • 相关阅读:
    Loadrunner日志设置与查看
    Mysqlfunc.c
    loadrunner生成随机uuid的方法
    数据库连接
    FAQ_2
    JAVA VUser
    FAQ_1
    LoadRunner中的Web 函数列表
    MySQL性能诊断与调优
    LoadRunner书籍推荐
  • 原文地址:https://www.cnblogs.com/yuefeng123/p/14758475.html
Copyright © 2011-2022 走看看