JUC中的AQS底层详细超详解( 二 )

  • CONDITION(-2) : 点在等待队列中 , 节点线程等待在Condition上 , 当其他线程对Condition调用了signal()后 , 改节点将会从等待队列中转移到同步队列中 , 加入到同步状态的获取中
  • PROPAGATE(-3) : 表示下一次共享式同步状态获取将会无条件地传播下去
  • INIT( 0):
  • 入队是怎么保证安全的?入队过程可能引发冲突
    因此会用CAS保障入队安全 。
    private Node enq(final Node node) { //多次尝试 , 直到成功为止 for (;;) { Node t = tail; //tail不存在 , 设置为首节点 if (t == null) { if (compareAndSetHead(new Node()))tail = head; } else { //设置为尾节点 node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }出队过程会发生什么?一旦有节点出队 , 说明有线程释放资源了 , 队头的等待线程可以开始尝试获取了 。
    于是首节点的线程释放同步状态后 , 将会唤醒它的后继节点(next)
    而后继节点将会在获取同步状态成功时将自己设置为首节点
    注意在这个过程是不需要使用CAS来保证的 , 因为只有一个线程能够成功获取到同步状态
    AQS详细资源获取流程1. tryAcquire尝试获取资源AQS使用的设计模式是模板方法模式 。
    具体代码如下:
    public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 发现中断过 , 则触发中断异常 selfInterrupt();}即AQS抽象基类AbstractQueuedSynchronizer给外部调用时 , 都是调的acquire(int arg)方法 。这个方法的内容是写死的 。而acquire中 , 需要调用tryAcquire(arg) ,  这个方法是需要子类实现的 , 作用是判断资源是否足够获取arg个
    (下面部分代码注释选自: (2条消息) AQS子类的tryAcquire和tryRelease的实现_Mutou_ren的博客-CSDN博客_aqs tryacquire )
    ReentrantLock中的tryAcquire实现这里暂时只谈论一种容易理解的tryAcuire实现 , 其他附加特性的tryAcquire先不提 。
    里面主要就做这几件事:
    1. 获取当前锁的资源数
    2. 资源数为0 , 说明可以抢 ,  确认是前置节点是头节点 , 进行CAS试图争抢 , 抢成功就返回true , 并设置当前线程
    3. 没抢成功 , 返回false
    4. 如果是重入的 , 则直接set设置增加后的状态值 , 状态值此时不一定为0和1了
    protected final boolean tryAcquire(int acquires){ final Thread current = Thread.currentThread(); int c = getState(); // state==0代表当前没有锁 , 可以进行获取 if (c == 0) { // 非公平才有的判断 , 会判断是否还有前驱节点 , 直接自己为头节点了或者同步队列空了才会继续后面的锁的获取操作 if (!hasQueuedPredecessors() //CAS设置state为acquires , 成功后标记exclusiveOwnerThread为当前线程 && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 当前占有线程等于自己 , 代表重入 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; // 出现负数 , 说明溢出了 if (nextc < 0) // throw new Error("Maximum lock count exceeded"); // 因为是重入操作 , 可以直接进行state的增加 , 所以不需要CAS setState(nextc); return true; } return false;}2.addWaiter 添加到等待队列当获取资源失败 , 会进行addWaiter(Node.EXCLUSIVE) ,  arg) 。
    目的是创建一个等待节点Node , 并添加到等待队列
    private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; // 通过CAS竞争队尾 if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } // 竞争队尾失败 , 于是进行CAS频繁循环竞争队尾 enq(node); return node; } private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize if (compareAndSetHead(new Node()))tail = head; } else { node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }

    经验总结扩展阅读