ReentrantLock的AQS实现原理

1.继承图

Lock接口负责给各种锁提供需要实现的方法模板

Sync是ReentrantLock的内部类,继承自AQS

AQS继承自AOS

2.非公平锁的加锁流程

构造方法 (ReentrantLock类中)

public ReentrantLock() {
        sync = new NonfairSync();
    }

 加锁方法 (ReentrantLock类中)

public void lock() {
        sync.lock();
    }

NonfairSync的lock()        (ReentrantLock类中)

final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

加锁成功

使用cas把state的值从0修改为1,说明加锁成功,调用AOS的方法把当前线程设置为独占线程。

加锁失败

使用cas修改state的值失败,说明加锁失败,调用AQS中的acquire()方法。

acquire(1)  (AQS类)

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

① tryAcquire(1):该方法作用是加锁失败后再尝试加一次锁

 AQS中只是提供了tryAcquire方法的模板,在NonfairSync类中重写该方法

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

②tryAcquire(1)方法仍然加锁失败的话,调用acquireQueued(addWaiter(Node.EXCLUSIVE), arg))  将该线程加入等待队列。

private Node addWaiter(Node node) {
        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;
    }
    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);
        }
    }

addWaiter方法是将Node节点互相连接起来形成一个双向链表

acquireQueued()是将节点加入进等待队列

大体流程如下:

假如该节点是第一个进入队列的,会先自动创建一个值为空的节点dummy,让head指向dummy,然后将第一个节点挂载到dummy后面,并将dummy的waitState值设置为-1,并将tail指向第一个节点。

如果该节点入队时不是第一个节点,则挂载到tail指向的节点之后,并将tail指向新加入的节点。

如果当前节点是第一个有效节点(前一个节点是dummy),则调用acquireQueued()时,会再尝试两次加锁,失败则会用LockSupport.park()进入阻塞,如果当前节点不是第一个有效节点,那么直接进入阻塞。

当前持有锁的线程unLock()以后,会唤醒阻塞的线程节点,依次出队使用锁。 

3.非公平锁的含义

非公平锁是指,如果当前占有锁的线程释放锁以后,阻塞队列的第一个有效节点和在此刻新启动的线程同时抢占锁,如果新启动的线程抢占成功,则阻塞队列的第一个有效节点继续阻塞。

4.解锁流程

unlock() (ReentrantLock类中)

public void unlock() {
        sync.release(1);
    }

 AQS的release方法 (AQS类中)

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease()方法由NonfairSync和fairSync实现,但这两个同步器类公用一个方法

(ReentrantLock类中)

protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

release()方法释放锁后,会unpark()阻塞队列的第一个有效节点Node,Node中存储的成员变量为Thread,试图抢占锁,抢占成功的话,第一个有效节点变为dummy,最初的dummy断开连接被回收,第一个有效节点的值设置为null,waitState设置为0。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值