AbstractQueuedSynchronizer 原理分析

来源:互联网 发布:知乎 个性签名 编辑:程序博客网 时间:2024/06/05 19:10

简介

  • 首先各种blocking lock 和 synchronizers (semaphores, events, etc)都是依赖于FIFO队列的。而AbstractQueuedSynchronizer 通过一个整型(int)的数值表示当前队列的状态,子类中可以通过getState/setStatye/compareAndSetState方法来改变队列状态。
  • 两种模式:
    • 共享模式 shared mode 线程共享
    • 排他模式 exclusive mode 线程独占

数据结构

Queue中的节点 - Node

Node{    int waitState;    Node prev;    Node next;    Thread thread;//该节点加入队列时的线程    Node nextWaiter;//等待Condition的节点}

Node 中定义了Queue的运行模式shared/exclusive(default)

static final Node SHARED = new Node();static final Node EXCLUSIVE = null;

waitStatus(节点状态):

  • CANCELLED 1 由于超时、被打断导致cancel。该线程不会再被阻塞。
  • SIGNAL -1 这个记号表示当前node之后的节点已经或即将被阻塞,需要再release或者cancel后唤醒一个或若干个后续节点,在该节点被release/cancel的时候,需要唤醒后面的节点。
  • CONDITION -2表示该节点处于CONDITION队列中。
  • PROPAGATE -3 当前场景下后续的acquireShared能够得以执行。
  • 0 表示当前节点在队列中,等待获取锁。

AbstractQueuedSynchronizer 持有Queue

{    Node head;    Node tail;    int state;}

AbstractQueuedSynchronizer 操作Queue

    getState();    setState();    Node enq(final Node node)//insert node;    Node addWaiter(Node mode)// add waiter - shared/exclusive node    //唤醒后面节点    private void unparkSuccessor(Node node) {        int ws = node.waitStatus;        if (ws < 0)            compareAndSetWaitStatus(node, ws, 0);//更新为0,表示等待锁        Node s = node.next;        if (s == null || s.waitStatus > 0) {            s = null;            //从tail开始查找non-canceled node,然后唤醒他。            for (Node t = tail; t != null && t != node; t = t.prev)                if (t.waitStatus <= 0)                    s = t;        }        if (s != null)            LockSupport.unpark(s.thread);    }

同步器实现

  • 获取
public final void acquire(int arg) {        if (!tryAcquire(arg) && //tryAcquire()获取arg状态,依赖子类具体实现            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//获取失败,将该节点插入tail,再次尝试获取。            selfInterrupt();    }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);        }    }

从上面的代码中可以看出,acquire会忽略Interruption,为此代码提供者还实现了可终止的方法来获取状态-抛异常。

public final void acquireInterruptibly(int arg)            throws InterruptedException {        if (Thread.interrupted())            throw new InterruptedException();        if (!tryAcquire(arg))            doAcquireInterruptibly(arg);    }    //doAcquireInterruptibly 处理方式同上面的处理方式是相似的,只不过在获取失败的时候,会抛异常 throw new InterruptedException();
  • release
public final boolean release(int arg) {        if (tryRelease(arg)) {//尝试释放状态            Node h = head;//获取头结点,头结点表示正在使用中的状态            if (h != null && h.waitStatus != 0)                unparkSuccessor(h);//唤起下一个节点            return true;        }        return false;    }private void unparkSuccessor(Node node) {        int ws = node.waitStatus;        if (ws < 0)//正在占用锁            compareAndSetWaitStatus(node, ws, 0);        Node s = node.next;        //获取需要唤醒的节点        if (s == null || s.waitStatus > 0) {            s = null;            for (Node t = tail; t != null && t != node; t = t.prev)                if (t.waitStatus <= 0)                    s = t;        }        if (s != null)            LockSupport.unpark(s.thread);//唤醒节点    }

ReentrantLock#FairSync 中的实现

  • lock
final void lock() {  acquire(1);}//AbstractQueuedSynchronizer#acquire()public final void acquire(int arg) {        if (!tryAcquire(arg) &&            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))            selfInterrupt();    } // ReentrantLock#FairSync#tryAcquire protected final boolean tryAcquire(int acquires) {            final Thread current = Thread.currentThread();            int c = getState();//获取当前队列的状态            if (c == 0) {//state == 0,代表可以被获取                if (!hasQueuedPredecessors() && //当前队列非空而且持有该锁的线程非当前线程。                    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");                setState(nextc);//设置状态值                return true;            }            return false;        }
  • release
protected final boolean tryRelease(int releases) {            int c = getState() - releases;//正常情况下,getState() 和releases是相等的。            if (Thread.currentThread() != getExclusiveOwnerThread())                throw new IllegalMonitorStateException();            boolean free = false;            if (c == 0) {                free = true;                setExclusiveOwnerThread(null);//            }            setState(c);            return free;        }

疑问点:

  1. unparkSuccessor 中 查找non-canceled node 为什么需要从tail开始查找?
阅读全文
1 0
原创粉丝点击