AQS源码学习

什么是Node以及为什么Node中要有Thread?

  1. AQS的排队和唤醒机制是用Node形成的队列实现的
  2. 只有把Thread放入队列中,才能被唤醒

加锁的逻辑(lock()方法)

  • lock方法是在Lock接口中定义的
  • 如果自己判断当前线程是不是获取锁的第一个线程,第一个想法就是判断一下当前队列是不是空的,但是源码中不是这样简单判断的。源码为:
public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
    //  h!=t判断的是:当前队列没有结点
    // h.next==null || h.next.thread!=Thread.currentThread() 判断的是:
    //队列没有结点或者首结点不是当前线程
    //总结起来就是:判断当前队列不为空,且第一个排列的线程不是本线程
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

公平锁的实现:

static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) { //如果可以被获取
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    //如果不是第一个要获取的线程,就返回false
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                //如果不可被获取,但是当前处理的正好是本线程,就+1
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            //其余情况返回false
            return false;
        }
    }

非公平锁的实现:

  static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                //只要调用lock方法,就CAS去修改当前的State
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }


final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {//如果可以被获取
        if (compareAndSetState(0, acquires)) {//就尝试设置state为1
            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;
}

定义在AQS类中的模板方法:

 public final void acquire(int arg) {
        if (!tryAcquire(arg) && //如果获取锁成功,直接返回
            //如果获取锁失败,将当前的线程加在请求队列的队尾,
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            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);
                    //再尝试一次获取锁,如果获取成功,就出队;并且把head往后挪一个,新
                    //的头结点就是当前结点
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //不是头结点 ,或者获取不成功
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }


	/**
     * Checks and updates status for a node that failed to acquire.
     * Returns true if thread should block. This is the main signal
     * control in all acquire loops.  Requires that pred == node.prev.
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     */
pred代表的是前驱结点,node代表的是当前结点
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)//ws=-1
            /*
            SIGNAL: The successor of this node is (or will soon be) blocked (via park), so the current node must unpark its successor when it releases or cancels. To avoid races, acquire methods must first indicate they need a signal, then retry the atomic acquire, and then, on failure, block. */
            /**
            signal:代表的意思是 这个结点正在被阻塞
            */
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {// ws=0 
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

总结下来就是:公平的实现会去按照先来后到的原则去尝试获取锁,而非公平的实现就立即尝试去获取锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值