欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JUC代码浅析[2]——基于AQS的锁ReentrantLock

程序员文章站 2022-06-07 20:45:57
...

JUC代码浅析[2]——基于AQS的锁ReentrantLock

         ReentrantLock是使用比较普遍的一个可重入锁,它是互斥的,一个锁只能被一个线程占有。它的方法基本都是委托给继承AQSSync实现的。其中Sync有两种实现,公平和非公平。Sync使用state(通过AQS暴露的getStatesetState方法)保存线程的获取次数。总的策略为state次数为0时可以获得锁。大于0时,如果当前线程已经拥有该锁则可再次获得,否则进入AQS的调度逻辑(<JUC代码浅析——同步器AQS>中介绍)。下面为非公平ReentrantLockNonfairSync实现,

        final void lock() {

            if (compareAndSetState(0, 1))

                setExclusiveOwnerThread(Thread.currentThread());

            else

                acquire(1);

        }

如果state次数为0的话,获得成功并设置当前线程为锁的拥有者。

否则进入AQS调度,acquire(1)方法使用tryAcquire尝试获得,这里重载的tryAcquire调用的是nonfairTryAcquire方法

        final boolean nonfairTryAcquire(int acquires) {

            final Thread current = Thread.currentThread();

            int c = getState();

           //如果当前重进入数为0,有机会取得锁

            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;

            }

       //都不满足,则进入AQS队列等待调度

            return false;

        }

 

公平ReentrantLockFairSync实现

protected final boolean tryAcquire(int acquires) {

            final Thread current = Thread.currentThread();

            int c = getState();

       //如果当前重进入数为0,有机会取得锁

            if (c == 0) {

           //如果当前线程是第一个等待者,获得成功并设置当前线程为锁的拥有者

                if (isFirst(current) &&

                    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;

            }

       //都不满足,则进入AQS队列等待调度

            return false;

        }

 

       fairSyncNonfairSynctryRelease方法是同一个,比较简单,就是改变一下state次数,如果需要的话把拥有者线程置为null

        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;

        }

 

       公平和非公平的区别就在于,尝试进入的时候需要判断当前线程是否是队列的第一个,是第一个才能进入。这样AQS在调度的时候就会阻塞掉很多线程,性能差别就比较大。ReentrantLock只支持互斥模式,没有共享模式