ReentrantLock源码解析

上一篇说到的显示锁(Lock),并且知道显示锁比synchronized更加灵活,ReentrantLock作为Lock的实现类,这一篇看下ReentrantLock的源码。

ReentrantLock类

 

构造方法:可以直接通过构造器创建ReentrantLock对象,公平锁和非公平锁在之后会有介绍

    /**默认构造器:非公平锁*/
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**带参构造器:通过fair设置公平锁或非公平锁*/
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

 lock等方法:通过其内部静态类Sync实现的,Sync继承AQS

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

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    .
    .
    .
    

非公平锁(NonfairSync)的获取

1)、NonfairSync,ReentrantLock的内部类

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

    final void lock() {
        if (compareAndSetState(0, 1)) { //CAS获取锁(修改锁状态成功则获取锁成功)
            setExclusiveOwnerThread(Thread.currentThread()); //设置当前线程为拥有独占访问权限的线程
        } else {
            acquire(1); //以独占锁的方式去获取锁,具体方法在AbstractQueuedSynchronizer中
        }
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires); //尝试获取非公平锁,上面acquire(1)中会用到这个,在Sync中
    }
}

2)、acquire(int arg),AQS中的方法,以独占锁的方式去获取锁

    public final void acquire(int arg) {
        //尝试获取锁,获取成功则返回,不成功则添加到等待队列中,线程执行interrupt(),安全中断
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

   
    private static void selfInterrupt() {
        Thread.currentThread().interrupt();//中断当前线程
    }

 3)、 nonfairTryAcquire(int acquires),Sync中方法,尝试获取不公平锁

    final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();//获取锁的状态
            if (c == 0) {//锁未被占用
                if (compareAndSetState(0, acquires)) {//CAS获取锁
                    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;
        }

4)、addWaiter(Node mode),AQS中的方法,通过给定模式为当前线程创建排队节点

    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);//为当前线程新建一个Node对象
        Node pred = tail;//同步队列尾节点
        if (pred != null) {//同步队列尾节点存在,同步队列不为空,将当前线程的Node对象加到同步队列后
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);//同步队列为空,则调用enq方法,新建同步队列,并将node加到队列中
        return node;
    }

5)、 enq(final Node node),AQS中的方法,将节点插入同步队列,同步队列为空则初始化

    private Node enq(final Node node) {
        //同步为空,初始化,再将node加入同步队列;同步队列不为空,直接将node加到队列中
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

 6)、acquireQueued(final Node node, int arg),AQS中的方法,以独占且不可中断的方式获取同步状态

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {//想获取锁的线程在它前一节点为head时就进行自旋,检查前一节点是否释放锁;一单释放锁,当前节点就能拿到锁
                final Node p = node.predecessor();//获取当前节点前一节点
                if (p == head && tryAcquire(arg)) {//p节点是head节点,尝试性获取锁,获取锁过程只是一个判断,不会存在开销问题,这样既能提高性能,避免阻塞,又能执行抢占锁的操作。
                    setHead(node);//将当前节点设置为head节点
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                 //判断p节点是否是同步队列的head节点,如果不是,则需要判断当前线程是否需要进入waiting状态;如果需要,则park()让当前线程进入waiting状态
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;//中断标识设置为true
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
​

 7)、shouldParkAfterFailedAcquire(Node pred, Node node),AQS中的方法,获取当前节点前一节点的状态,然后对当前节点进行对应的操作

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) { 
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

8)、parkAndCheckInterrupt(),AQS中的方法,pack使线程进入waiting状态,并返回中断标识,Thread.interrupted()之后会将线程中断标识重置为false

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

9)、cancelAcquire(Node node),AQS中方法,取消正在进行的获取尝试

    private void cancelAcquire(Node node) {
        if (node == null)//如果node不存在,直接返回
            return;

        node.thread = null;//

        Node pred = node.prev;
        while (pred.waitStatus > 0)//pred节点被取消
            node.prev = pred = pred.prev;

        Node predNext = pred.next;

        node.waitStatus = Node.CANCELLED;//node状态
        
        if (node == tail && compareAndSetTail(node, pred)) {//如果node节点是队列中的tail节点,则移除
            compareAndSetNext(pred, predNext, null);
        } else {
            int ws;
            //如果node不是tail节点,也不是head的后一节点,则将node的前一节点的waitStatus置为SIGNAL,并使node的前一节点指向node的后一节点
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {
                unparkSuccessor(node);//node节点是head的后一节点,则唤醒它
            }
            node.next = node; // help GC
        }
    }

 FairSync(公平锁)的获取

1)、FairSync ,ReentrantLock的内部类

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

        final void lock() {
            acquire(1);//与非公平锁中获取独占锁一致
        }

        /**尝试获取锁*/
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();//获取锁的状态
            if (c == 0) {//没有线程获取锁
                //判断当前线程是否是同步队列中的第一个线程,是则CAS操作获取锁,修改锁状态
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);//当前线程占据锁
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {//重入判断,锁被占用情况下,判断是否是当前线程占用
                int nextc = c + acquires;
                if (nextc < 0)//超过最大锁计数
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);//设置锁的状态值
                return true;
            }
            return false;
        }
    }

2)、acquire(int arg),AQS中的方法,以独占锁的方式去获取锁,与非公平锁的tryAcquire(int acquires)方法不同

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

锁的释放

1)、unlock(),ReentrantLock中方法,释放锁的入口

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

 2)、  release(int arg),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;
    }

    protected boolean tryRelease(int arg) {
        throw new UnsupportedOperationException();
    }

 3)、tryRelease(int releases),Sync中方法,尝试以独占模式释放资源

    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;//锁的状态值-1
        if (Thread.currentThread() != getExclusiveOwnerThread())//当前线程不是拥有独占访问权限的线程,抛出异常
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) {
            free = true;
            setExclusiveOwnerThread(null);//清空占据锁的线程信息
        }
        setState(c);//更新锁的状态值
        return free;
    }

4)、unparkSuccessor(Node node),AQS中方法,唤醒等待队列中下一个线程

    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);//如果队列中存在下一个线程,唤醒它
    }

可中断的获取锁

1)、lockInterruptibly(),ReentrantLock中方法,可中断地获取锁入口

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

2)、acquireInterruptibly(int arg),AQS中方法,以独占模式获取,如果中断则中止

    public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())//检查线程标志位,true表示线程中断,调用后会重置为false
            throw new InterruptedException();
        if (!tryAcquire(arg))//尝试获取锁
            doAcquireInterruptibly(arg);//以独占可中断模式获取锁
    }

 3)、doAcquireInterruptibly(int arg),AQS中方法,以独占可中断模式获取锁

    private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);//为当前线程创建独占模式节点,添加到同步队列
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();//获取当前节点前一节点
                if (p == head && tryAcquire(arg)) {
                    setHead(node);将当前节点设置设置为head节点
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

其他方法就不一一解析了,有兴趣的朋友可以自己去看看。

注意:看这部分源码的时候,发现:NonfairSync/FairSync继承Sync,Sync继承了AbstractQueuedSynchronizer,这里就有一个多重继承。为什么能够多重继承?NonfairSync、FairSync、Sync都是ReentrantLock的内部类,内部类可以继承一个与外部类无关的类,保证了内部类的独立性,所以这里才可以多重继承。

 

 

如果有写的不对的地方,请大家多多批评指正,非常感谢!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值