ReentrantLock源码实现(上)

ReentrantLock的实现依赖于Sync

  • Sync是ReentrantLock中的抽象静态内部类,继承自AQS(AbstractQueuedSynchronizer)
  • 其子类实现有两个:FairSync、NonfairSync;
  • 使用AQS#state来表示持有当前锁对象的线程个数。
public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;

    /**
     * Base of synchronization control for this lock. Subclassed
     * into fair and nonfair versions below. Uses AQS state to
     * represent the number of holds on the lock.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
    	...
    }
    
    public void lock() {
        sync.lock();
    }

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

1. lock操作

1.1 NonfairSync实现

NonfairSync#lock()

        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
  1. 通过CAS操作来修改state的状态,
    如果state为0,则将其置为1,表示获取锁成功,并将当前线程设置为ownerThread(独占线程);
  2. 获取锁失败,则调用AQS#acquire方法来进行后续处理

AbstractQueuedSynchronizer#acquire(int arg)

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

acquire方法分解为3个步骤:

  1. 尝试获取锁,成功则退出方法
  2. 尝试获取锁失败,则调用addWaiter将当前线程以独占Node的形式添加到等待队列尾部
  3. 调用acquireQueued处理队列中的节点,通过自旋的形式尝试获取锁(内部是无条件for循环实现自旋)
  4. 中断当前线程interrupt

2.2 FairSync实现

FairSync#lock()

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

公平锁lock()操作较为简单,直接调用AQS#acquire(), 具体见非公平锁的描述。

2. tryLock操作

ReentrantLock#tryLock()

 public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

Sync#nonfairTryAcquire()

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            // 1. 
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 2.
            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;
        }

公平锁与非公平锁的tryLock()操作是一样的,都是调用Sync#nonfairTryAcquire()

  1. 获取当前线程,调用AQS#getState()判断锁状态, 锁状态为0,表示无锁状态,通过CAS操作 更新state的值,返回true;
  2. 锁状态不为0,进一步判断是否为当前独占线程,如果是,则当前线程是重入,更新重入次数nextc,返回true;
  3. 其他情况属于获取锁失败,返回false

3. unLock操作

非公平锁与公平锁的unLock操作是一样的,都是调用AQS#release()方法。

3.1 AQS#release(int arg)

    public final boolean release(int arg) {
    	// 更新state=(state-arg)标志,state为0 返回true,其他返回false
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

调用AQS#unparkSuccessor()

    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            node.compareAndSetWaitStatus(ws, 0);
            
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            // 1.
            for (Node p = tail; p != node && p != null; p = p.prev)
                if (p.waitStatus <= 0)
                    s = p;
        }
        // 2.
        if (s != null)
            LockSupport.unpark(s.thread);
    }
  1. 默认是唤醒队首节点s,如果s取消了或者为null,则反转从队尾往队首找,找到第一个waitStatus<=0的节点;
  2. 节点不为空,则唤醒节点对应的线程

4.总结

  1. ReentrantLock中加锁/释放锁节点,多次用到CAS操作,这是有硬件保证的并发安全的操作;
  2. ReentrantLock的lock操作,获取锁失败,创建独占节点,所以ReentrantLock是独占锁。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值