Jen 发表于 2013-2-1 12:12:08

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

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

         ReentrantLock是使用比较普遍的一个可重入锁,它是互斥的,一个锁只能被一个线程占有。它的方法基本都是委托给继承AQS的Sync实现的。其中Sync有两种实现,公平和非公平。Sync使用state(通过AQS暴露的getState和setState方法)保存线程的获取次数。总的策略为state次数为0时可以获得锁。大于0时,如果当前线程已经拥有该锁则可再次获得,否则进入AQS的调度逻辑(<JUC代码浅析——同步器AQS>中介绍)。下面为非公平ReentrantLock的NonfairSync实现,
        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("Maximumlock count exceeded");
                setState(nextc);
                return true;
            }
       //都不满足,则进入AQS队列等待调度
            return false;
        }
 
公平ReentrantLock的FairSync实现
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("Maximumlock count exceeded");
                setState(nextc);
                return true;
            }
       //都不满足,则进入AQS队列等待调度
            return false;
        }
 
       fairSync和NonfairSync的tryRelease方法是同一个,比较简单,就是改变一下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只支持互斥模式,没有共享模式
 
页: [1]
查看完整版本: JUC代码浅析[2]——基于AQS的锁ReentrantLock