洛城小红魔

科比 曼联 程序员

Lock, AQS


AQS  队列同步器

        同步器是实现锁(也可以是任意同步组件)的关键,在锁的实现中聚合同步器,利用同步
器实现锁的语义。可以这样理解二者之间的关系:锁是面向使用者的,它定义了使用者与锁交
互的接口(比如可以允许两个线程并行访问),隐藏了实现细节;同步器面向的是锁的实现者,
它简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。锁和同

步器很好地隔离了使用者和实现者所需关注的领域.

        同步器的设计是基于模板方法模式的,也就是说,使用者需要继承同步器并重写指定的
方法,随后将同步器组合在自定义同步组件的实现中,并调用同步器提供的模板方法,而这些
模板方法将会调用使用者重写的方法。
        重写同步器指定的方法时,需要使用同步器提供的如下3个方法来访问或修改同步状态。
        ·getState():获取当前同步状态。
        ·setState(int newState):设置当前同步状态。
        ·compareAndSetState(int expect,int update):使用CAS设置当前状态,该方法能够保证状态
设置的原子性。


同步器的acquire方法

        同步状态获取、节点构造、加入同步队列以及在同步队列中自旋等
待的相关工作,其主要逻辑是:首先调用自定义同步器实现的tryAcquire(int arg)方法,该方法
保证线程安全的获取同步状态,如果同步状态获取失败,则构造同步节点(独占式
Node.EXCLUSIVE,同一时刻只能有一个线程成功获取同步状态)并通过addWaiter(Node node)
方法将该节点加入到同步队列的尾部,最后调用acquireQueued(Node node,int arg)方法,使得该
节点以“死循环”的方式获取同步状态。如果获取不到则阻塞节点中的线程,而被阻塞线程的
唤醒主要依靠前驱节点的出队或阻塞线程被中断来实

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
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;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    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;
            }
        }
    }
}
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
/*设置等待*/
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); }}



      在获取同步状态时,同步器维护一个同步队列,获取状态失败的线程都会被加入到队列中并在队列中进行自旋;移出队列(或停止自旋)的条件是前驱节点为头节点且成功获取了同步状态。在释放同步状态时,同步器调用tryRelease(int arg)方法释放同步状态,然后唤醒头节点的后继节点。


共享式同步状态获取与释放





重入锁ReentrantLock

公平锁,非公平锁(效率高)




阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18838463/article/details/80350340
个人分类: java
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

Lock, AQS

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭