java源码阅读之深入理解AQS

先翻译源码介绍

写得不太好,大家不要浪费时间看了

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic {@code int} value to represent state. Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being acquired or released. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updated {@code int} value manipulated using methods {@link #getState}, {@link #setState} and {@link #compareAndSetState} is tracked with respect to synchronization.

  • 提供一个实现依赖先进先出的等待队列的阻塞锁和相关的同步器的框架。这个类被设计用来为大多数依赖一个原子value来代表其状态的同步器提供一个实用的基础。子类必须定义那些protected方法来改变状态,并且还要还通过得到的和释放的实例化对象来定义那些状态的含义。有了它们,这个类中其它方法用来实施所有的队列和阻塞技术。子类可以维持别的状态字段,但是只有被原子更新的value被正在使用的方法操作,而且其被期望的同步来追踪(胡乱翻译的)。

This class supports either or both a default exclusive mode and a shared mode. When acquired in exclusive mode, attempted acquires by other threads cannot succeed. Shared mode acquires by multiple threads may (but need not) succeed. This class does not "understand" these differences except in the mechanical sense that when a shared mode acquire succeeds, the next waiting thread (if one exists) must also determine whether it can acquire as well. Threads waiting in the different modes share the same FIFO queue. Usually, implementation subclasses support only one of these modes, but both can come into play for example in a {@link ReadWriteLock}. Subclasses that support only exclusive or only shared modes need not define the methods supporting the unused mode.
*这个类支持独占模式和共享模式。在独占模式时,其它想要获得的线程都会失败。共享模式下被多个线程获得可能成功。这个类不会quot和understand quot;这两者的区别是下一个等待的线程(如果存在的话)还要必须决定其是否可以获得(除了在共享模式成功获得的情况下)。在不同模式等待下的线程们共享同样的先进先出的队列。通常情况下,子类仅支持其中一种模式,但是他们两个都可以进入活动。仅支持独占模式或仅支持共享模式的子类不需要定义那些支持其不使用的模式的方法。

This class provides inspection, instrumentation, and monitoring methods for the internal queue, as well as similar methods for condition objects. These can be exported as desired into classes using an {@code AbstractQueuedSynchronizer} for their synchronization mechanics.

  • 这个类对内部队列提供了检查,表格化和监控方法,并且有着和状态对象们相同的方法。这些方法可以像期望的那样输出到多个类中,为他们的同步技术使用一个AbstractQueuedSynchronizer

Serialization of this class stores only the underlying atomic integer maintaining state, so deserialized objects have empty thread queues. Typical subclasses requiring serializability will define a {@code readObject} method that restores this to a known initial state upon deserialization.

  • 类的序列化存储仅仅是维持状态的原子的integer,所以反序列化对象只有空的线程队列。典型的要求序列化的子类们将要定义一个为了一个已知的在反序列化之上的初始化状态来保存它的readObject方法

  • 后面的太长了懒得翻译,大意是AbstractQueuedSynchronizer利用CLH锁的一种变体来完成线程之间的排队和同步

  • 关于什么是CLH算法,链接中的博主讲的十分清楚了
    https://blog.csdn.net/dm_vincent/article/details/79842501

正题开始

先看内部静态类Node类定义

        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;
  • 这四个值为waitStatus的四种状态(初始化为0表示没有获得锁),其值为非负数时表明该结点不需要signal操作
  • CANCELLED 表示此节点因为超时或中断而被取消,结点永远不会离开此状态,所以线程再也不会被阻塞。
  • SIGNAL 这个结点的next节点被阻塞,当这个节点释放或取消资源时通知后继节点
  • CONDITION 表示此节点在condition队列中,其它结点调用condition.signal()后将其移动到同步队列且waitStatus被置为0,在这之前无意义
  • PROPAGATE 只有共享模式下的head结点有意义,表明可以向后传播

以下图为例解释各个字段的含义

== tail<——>结点1<——>结点2<——>head ==

	  private transient volatile Node head;
   
       private transient volatile Node tail;
       
   	//同步的资源
       private volatile int state;
		
		//当前结点的状态
       volatile int waitStatus;
       
       //结点1的prev为结点2
       volatile Node prev;
      
      	//结点1的next指向tail
       volatile Node next;
       
       //当前结点对应的thread
       volatile Thread thread;
   	
       Node nextWaiter;

继续看之前可以看一下java的varHandle,我也是看到这里现去学的,参考以下链接
https://blog.csdn.net/sench_z/article/details/79793741

加入队列方法,如果队列为空则初始化,返回其前驱结点

    private Node enq(Node node) {
        for (;;) {
            Node oldTail = tail;
            if (oldTail != null) {
                node.setPrevRelaxed(oldTail);
                if (compareAndSetTail(oldTail, node)) {
                    oldTail.next = node;
                    return oldTail;
                }
            } else {
                initializeSyncQueue();
            }
        }
    }

加入队列方法,如果队列为空则初始化,返回其前驱结点

    private Node addWaiter(Node mode) {
        Node node = new Node(mode);

        for (;;) {
            Node oldTail = tail;
            if (oldTail != null) {
                node.setPrevRelaxed(oldTail);
                if (compareAndSetTail(oldTail, node)) {
                    oldTail.next = node;
                    return node;
                }
            } else {
                initializeSyncQueue();
            }
        }
    }

唤醒下一结点

  • 如果下一个结点为空或其waitStatus>0则从tail往前找一个不为空的node,如果找到了则将其唤醒
private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            node.compareAndSetWaitStatus(ws, 0);
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node p = tail; p != node && p != null; p = p.prev)
                if (p.waitStatus <= 0)
                    s = p;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

共享模式下的释放操作

  • 执行完后head状态要么是0唤醒其后结点,要么为传播状态
    private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                // ws == Node.SIGNAL表明其后结点被阻塞,将这个结点的waitStatus置为0然后唤醒下一节点
                if (ws == Node.SIGNAL) {
                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                //如果其没有锁,将其waitStatus变为PROPAGATE
                else if (ws == 0 &&
                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

核心方法:让每一个结点自旋直到获取锁

  • 只有当一个结点的prev结点是head并且该节点可以获得同步状态时,return。否则不停等待阻塞,并且会删除canceled结点。
    final boolean acquireQueued(final Node node, int arg) {
    	//没有被阻塞
        boolean interrupted = false;
        try {
        	//开始自旋
            for (;;) {
            	//得到其prev结点
                final Node p = node.predecessor();
                //如果当前节点为第二个结点并且可以获取锁,那就把当前节点设为头节点,原头节点
                指向空值(为了垃圾回收)
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                  	//退出自旋
                    return interrupted;
                }
                //其余情况就阻塞自己开始自旋,关于shouldParkAfterFailedAcquire函数往下看,该结点的prev结点的值为SIGNAL时其返回true
                if (shouldParkAfterFailedAcquire(p, node))
                	//将当前线程阻塞
                    interrupted |= parkAndCheckInterrupt();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            if (interrupted)
                selfInterrupt();
            throw t;
        }
    }

shouldParkAfterFailedAcquire方法

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        //若其prev结点waitStatus为SIGNAL则返回true
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
        //如果被取消了,则该节点的prev一直向head方向取,直到<=0
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        }
        //如果为0或者被condition阻塞,则将该节点的waitStatus设为SIGNAL 
        else {
            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
        }
        //只有该结点的prev结点为SINAL时才返回true
        return false;
    }

下面这张图画的不错:
在这里插入图片描述

释放资源

  • 独占模式下释放资源
    protected boolean tryRelease(int arg) {
        throw new UnsupportedOperationException();
    }
  • 释放成功后唤醒头节点之后的结点
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

先写到这里,哪天有时间继续写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值