源码学习之ReentrantLock

首先参考http://www.cnblogs.com/skywang12345/p/3496098.html(多线程系列讲得挺好的)
什么是ReentrantLock?
ReentrantLock是独占锁、可重入锁。所谓独占锁,是指只能被独自占领,即同一个时间点只能被一个线程锁获取到的锁。所谓可重入锁,ReentrantLock锁可以被单个线程多次获取。
ReentrantLock类图

(01) ReentrantLock实现了Lock接口。
(02) ReentrantLock中有一个成员变量sync,sync是Sync类型;Sync是一个抽象类,而且它继承于AQS。
(03) ReentrantLock中有”公平锁类”FairSync和”非公平锁类”NonfairSync,它们都是Sync的子类。ReentrantReadWriteLock中sync对象,是FairSync与NonfairSync中的一种,这也意味着ReentrantLock是”公平锁”或”非公平锁”中的一种,ReentrantLock默认是非公平锁。

源码分析

public class ReentrantLock implements Lock, java.io.Serializable {
...
}

首先从整体来看,ReentrantLock是一个实现Lock与java.io.Serializable接口的类。
父接口:Lock类

public interface Lock {
    //获取锁的方法
    void lock();
    //如果可以获取锁,则立即返回;获取锁的时候优先相应中断(而不是获取锁),并且抛出中断异常
    void lockInterruptibly() throws InterruptedException;
    //如果可以获得锁,则返回true;如果锁被其他线程获取,则返回false;
    boolean tryLock();
    //与tryLock相比,设置等待时间,如果在设置的时间之内获得了锁,则返回true;不能获得锁,或者没有在设置的时间内获得锁,则返回false;并且当等待获得锁的时候被中断,则抛出中断异常。
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    //释放锁;
    void unlock();
    //返回一个新的Condition实例;
    Condition newCondition();
}

父接口:java.io.Serializable
java.io.Serializable是一个标记接口,没有任何的抽象方法,其作用是表明实现此接口的类可以进行序列化和反序列化,Java的”对象序列化”能让你将一个实现了Serializable接口的对象转换成byte流,这样日后要用这个对象时候,你就能把这些byte数据恢复出来,并据此重新构建那个对象了。

接下来继续看源码,发现ReentrantLock中有好几个内部类;

abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -5179523762034025860L;
    abstract void lock();
    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;
        }

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

    protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

    final ConditionObject newCondition() {
            return new ConditionObject();
        }  

    final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

    final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

    final boolean isLocked() {
            return getState() != 0;
        }

    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }                

Sync的官方API解释:基于锁的同步控制,其子类分为公平和非公平两个版本,使用AQS(AbstractQueuedSynchronizer)的状态代表对锁的持有数量。
Sync类继承AbstractQueuedSynchronizer类。在Sync的nonfairTryAcquire(int acquires)方法中出现了一个int型变量c。其值为getState(),getState()方法是AQS中的一个方法,其返回一个状态,此状态在Sync中作为一个线程持有的锁数量;当持有锁的数量为0时,它会设置占有锁的线程为当前线程,并且返回true。如果持有锁的数量不为0,则首先判断当前线程是否是一个独占锁的线程,然后设置线程持有锁的数量为初始数量c加上acquires数量的值(表现出可重入的特性)。
接下来就是Sync的两个子类,NonfairSync与FairSync
NonfairSync类比较简单,只有两个方法

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

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

lock()方法表示创建一个非公平的独占锁,并且将锁的状态即线程持有锁的数量设置为1。若当前线程持有锁,则执行tryAcquire()方法。
tryAcquire()方法直接调用的是Sync的nonfairTryAcquire()非公平获取锁的方法。
公平锁源码如下:

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

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

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                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;
        }
    }

FairSync公平锁,在创建锁时要执行公平策略:如果锁被占用且当前线程不是持有者也不是等待队列的第一个,则进入等待队列(AQS就是一个先进先出的等待锁队列)。
公平锁创建锁时,直接依赖执行tryAcquire()方法。
公平版本的tryAcquire(),当锁空闲时即c=0,会判断有没有等待队列和当前线程是不是等待队列的第一个,若没有等待队列或者是等待队列的第一个,且会尝试去利用CAS获取锁,成功之后就会设置锁的持有者为当前线程,这就是在获取锁的公平获取策略。同样若锁被当前线程持有,则增加线程持有锁的数量,即可重入。
非公平锁和公平锁都是继承Sync,所以形式上相同,唯一的区别是当当前线程不持有锁时,非公平锁将AQS状态设置为1,然后设置当前线程为锁的持有者。为公平锁则是先尝试去获取锁,若能够获取锁,再将当前线程锁持有状态(AQS)设置为1。

了解完ReentrantLock锁里面的内部类之后,其类中的其他方法都是依赖内部类来实现的,所以很好理解了。

//无参构造方法,默认是非公平的锁。
public ReentrantLock() {
        sync = new NonfairSync();
    }
//通过设置是否公平,来构造ReentrantLock锁;当为true时,构造公平锁,为false时,构造非公平锁。
public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
//获取锁,调用的是对应非公平锁和公平锁中的lock()方法    
public void lock() {
        sync.lock();
    }
//响应锁的中断,能够在获取锁时优先响应中断并抛出中断异常    
public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    } 
//尝试获取锁,调用的是非公平获取锁的方法    
public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
//设置获取锁的时间限制    
public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
//释放锁    
public void unlock() {
        sync.release(1);
    }
//Condition的作用是对锁进行更精确的控制,之后学习。
public Condition newCondition() {
        return sync.newCondition();
    }
//获得当前线程锁的持有数量。
public int getHoldCount() {
        return sync.getHoldCount();
    }  
//判断当前是不是持有锁    
public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }
//判断锁的状态,若任何线程持有锁则返回true,否则返回false  
public boolean isLocked() {
        return sync.isLocked();
    }
//判断锁是不是公平锁。 
public final boolean isFair() {
        return sync instanceof FairSync;
    }
//用来返回持有此锁的当前线程,若锁不被任何线程持有,则返回空。
protected Thread getOwner() {
        return sync.getOwner();
    } 
//判断这个锁是否有一个等待获取此锁的队列
public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }
//判断给定的线程是否是在等待获取锁的队列中,若是,返回true
public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }
//返回锁等待队列的长度
public final int getQueueLength() {
        return sync.getQueueLength();
    }
//获取锁等待队列中的线程集合
protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    } 
//下面的几个方法与Condition有关,之后再详细学习。                            

上面的方法都是有关获取锁、释放锁以及等待锁队列,ReentrantLock实际上与AQS有很大的关系,因为其实现的方法中都与Sync有关系,而Sync继承AQS,所以方法中有许多关于锁等待队列的判断及获取方法。ReentrantLock利用内部类来隐式的继承AQS,用户不会看到不需要的方法,也避免了用户错误地使用AbstractQueuedSynchronizer的公开方法而导致错误。
ReentrantLock锁源码大概就这么多,总结一下:ReentrantLock锁里有一个很重要的内部类Sync,其继承AQS类,有了锁的等待队列特性,同时Sync衍生出来两种锁:非公平锁和公平锁,利用等待队列的特性可实现公平获取锁的策略,用户可依据ReentrantLock去创建公平锁与非公平锁。在ReentrantLock方法中继承了Lock类的可中断锁的特性,以及获取锁等待队列的相关信息。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值