您的位置:首页 > 编程语言 > Java开发

java AQS 框架一些理解

2017-04-29 11:49 218 查看
最近感觉基础有待加强,写点理论加深下自己的理解 ,第一次写博客希望大家给点建议,指点下

AQS的全称为(AbstractQueuedSynchronizer);

JAVA 主要实现类为 AbstractQueuedSynchronizer(结构如下)


  AbstractQueuedSynchronizer主要结构入上图 

1.AbstractQueuedSynchronizer 主要有一个标志锁状态的state 和指向队列头和尾的指针(主要成员变量为 state (标志锁的状态) head  指向等待获取锁队列的头  tail
指向获取队列的尾部)

2.AbstractQueuedSynchronizer  有两个内部类 Node(对等待获取锁线程的一个封装) 和 ConditionObject   

下面结合ReentrantLock 源码分析下jdk怎么实现AQS(jdk1.7.0_67)

1.ReentrantLock 的构造函数两个ReentrantLock(),ReentrantLock(fair)

可以看到构造函数主要初始化sync 成员变量 ,下面以ReentrantLock()构造函数来说明;

初始化一个 sync = new NonfairSync(); NonfairSync继承Sync ,Sync
又继承AbstractQueuedSynchronizer

NonfairSync
主要实现 lock,tryAcquire;

2,我们看下ReentrantLock.lock
我们获取锁的入口函数

 public
void lock() {

        sync.lock();

    }

调用的是 
sync.lock();

sync的代码如下

 final
void lock() {

            if (compareAndSetState(0, 1))

                setExclusiveOwnerThread(Thread.currentThread());

            else

                acquire(1);

        }

acquire 方法是在AbstractQueuedSynchronizer 实现的,代码如下

  public final void acquire(int arg) {

        if (!tryAcquire(arg) &&

            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

            selfInterrupt();
    }

简单解释下上面代码compareAndSetState(0, 1) 利用CAS 原理修改AbstractQueuedSynchronizer 的成员变量state 如果修改成功则当前线程获取锁;

并把sync 锁所属线程设置成当前线程

 如果不成功 则调用acquire(1);

我们在看下acquire(1) 的执行流程

if(!tryAcquire(1)&&acquireQueued(addWaiter(Node.EXCLUSIVE), 1))

 selfInterrupt();

tryAcquire(1) 会调用 nonfairTryAcquire(1)

 final boolean nonfairTryAcquire(int acquires) {

            final Thread current = Thread.currentThread();

            int c = getState();

            if (c == 0) {

                if (compareAndSetState(0, acquires)) {

                    setExclusiveOwnerThread(current);

                    return true;

                }

            }

            else if (current == getExclusiveOwnerThread()) {

                int nextc = c + acquires;

                if (nextc < 0) // overflow

                    throw new Error("Maximum lock count exceeded");

                setState(nextc);

                return true;

            }

            return false;

        }

第一部分主要是当前线程继续尝试获取锁 第二个if是判断锁的持有者是不是当前线程

如果前两个if都没走则说明获取锁失败

继续走acquireQueued(addWaiter(Node.EXCLUSIVE), 

addWaiter方法是将没获取锁的线程组装成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;

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

        }

    }

这是个死循环 如果p == head && tryAcquire(arg) 不满足则会调用parkAndCheckInterrupt
阻塞线程

最终调用的是unsafe.park(false,
0L),阻塞线程这是个native方法这里不解释了 

3.最后我们看下unlock函数怎样释放锁的

 public
void unlock() {

        sync.release(1);

    }

 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) {

        /*

         * If status is negative (i.e., possibly needing signal) try

         * to clear in anticipation of signalling.  It is OK if this

         * fails or if status is changed by waiting thread.

         */

        int ws = node.waitStatus;

        if (ws < 0)

            compareAndSetWaitStatus(node, ws, 0);

        /*

         * Thread to unpark is held in successor, which is normally

         * just the next node.  But if cancelled or apparently null,

         * traverse backwards from tail to find the actual

         * non-cancelled successor.

         */

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

    }

主要是修改syn的状态变量 队列的移除,唤醒其他线程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java AQS