AbstractQueuedSynchronizer:独占锁

并发是java编程一个比较高级的一个点,自己也常常试用,但是对于并发怎么实现了,确实不明白,打算认真学习下,从AbstractQueuedSynchronizer开始吧,自己水平有限,如果有不对的地方,麻烦指出来.

AbstractQueuedSynchronizer是Countdownlatch,ReentrantLock,ThreadPoolExecutor,ReentrantReadWriteLock,Semaphore的基础.而AbstractQueuedSynchronizer继承AbstractOwnableSynchronizer.

AbstractOwnableSynchronizer

A synchronizer that may be exclusively owned by a thread. This class
provides a basis for creating locks and related synchronizers that may
entail a notion of ownership. The AbstractOwnableSynchronizer class
itself does not manage or use this information. However, subclasses
and tools may use appropriately maintained values to help control and
monitor access and provide diagnostics.

我的理解是,那个线程获得cpu或者临界资源吧.只有一个参数,Thread exclusiveOwnerThread;

Node

 static final class Node {
        static final Node SHARED = new Node();
        static final Node EXCLUSIVE = null;
        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;
        volatile int waitStatus;
        volatile Node prev;
        volatile Node next;
        volatile Thread thread;
        Node nextWaiter;

        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    
        }

        Node(Thread thread, Node mode) {    
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { 
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }
  • Node prev; 前驱节点
  • Node next; 后继节点。
  • Thread thread; 入队列时的当前线程。
  • waitStatus:表示节点的状态。其中包含的状态有:
    CANCELLED,值为1,表示当前的线程被取消;
    SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark;
    CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中;
    PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行;
    值为0,表示当前节点在sync队列中,等待着获取锁。
  • Node nextWaiter

    Link to next node waiting on condition, or the special value SHARED. Because condition queues are accessed only when holding in exclusive mode, we just need a simple linked queue to hold nodes while they are waiting on conditions. They are then transferred to the queue to re-acquire. And because conditions can only be exclusive, we save a field by using special value to indicate shared mode.
    存储condition队列中的后继节点。表示了两种不同的模式:
    1)共享模式(SHARED,允许多个线程通过);
    2)排它模式(EXCLUSIVE,只允许一个线程通过)。

  • Node predecessor();前任节点

    类的成员变量

  • Node head:Head of the wait queue, lazily initialized. Except for initialization, it is modified  only via method setHead. Note: If head exists, its waitStatus is guaranteed not to be    CANCELLED.

  • Node tail:Tail of the wait queue, lazily initialized. Modified only via method enq to add new wait node.
  • int state:The synchronization state.(标志临界资源是否获取,1:已经呗获取了,0:没有被获取)

    独占锁(EXCLUSIVE)

    acquire

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
  • tryAcquire:排它的获取这个状态。这个方法的实现需要查询当前状态是否允许获取,然后再进行获取(使用compareAndSetState来做)状态。

  • addWaiter:把当前线程节点放到队列尾

    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;
    }
  • acquireQueued
    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做一下总结:
1. 状态的维护;
需要在锁定时,需要维护一个状态(int类型),而对状态的操作是原子和非阻塞的,通过同步器提供的对状态访问的方法对状态进行操纵,并且利用compareAndSet来确保原子性的修改。
2. 状态的获取;
一旦成功的修改了状态,当前线程或者说节点,就被设置为头节点。
3. sync队列的维护。
在获取资源未果的过程中条件不符合的情况下(不该自己,前驱节点不是头节点或者没有获取到资源)进入睡眠状态,停止线程调度器对当前节点线程的调度。

###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;
    }

主要看下unparkSuccessor:如果存在后续节点,唤醒

    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);
    }

可以看出来,获取锁的节点,一直在队列头部

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章