看了下J.U.C并发包下的ReentrantLock源码,费了很多劲,作个小总结吧,尽可能用通俗易懂的语言描述,配上一些图说明。java
ReentrantLock介绍编程
ReentrantLock是基于AbstractQueuedSynchronizer(AQS框架)设计的,类里面有一个私有sync成员属性,其类型为AbstractQueuedSynchronizer;并发
那么什么是AQS框架呢?AQS是由大神Doug Lea设计的,他写了一篇论文叫《The java.util.concurrent Synchronizer Framework 》,里面详细描述了AQS的设计思想,想看中文翻译的,能够去并发编程网里阅读,连接。框架
我这里简要说明下,AQS主要是维护了一个int类型的state属性,一个非阻塞、先进先出的线程等待队列;其中state是用volatile修饰的,保证线程之间的可见性,队列的入队和出对操做都是无锁操做,基于自旋锁和CAS实现;另外AQS分为两种模式:独占模式和共享模式,本文讨论的ReentrantLock,主要涉及AQS的独占模式;源码分析
回过头来讲ReentrantLock,其内部有三个内部类Sync、NonfairSync和FairSync,其中NonfairSync和FairSync继承Sync,Sync继承AbstractQueuedSynchronizer,这三个内部类主要是为了实现父类AbstractQueuedSynchronizer中未实现的tryRelease(int)和tryAcquire(int)方法;ui
其实ReentrantLock类自己并无实现什么新功能,仔细观察其下面的方法,发现都是经过调用sync的方法去实现的,以下所示:spa
//省略前面部分... 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); } public Condition newCondition() { return sync.newCondition(); } public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } //省略后面部分...
源码分析线程
先看一下咱们平时都是怎样使用ReentrantLock的,以下代码:翻译
ReentrantLock lock = new ReentrantLock(); lock.lock(); try { // do something } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); }
这里的ReentrantLock是一个非公平独占锁,其保证do something在同一时刻只有一个线程能访问,当有线程正在执行do something里的代码时,其它线程将会等待。设计
那么,咱们就先从lock方法开始,分析ReentrantLock是如何实现非公平独占锁的;
ReentrantLock的lock方法调用的是sync的lock方法,而sync是在构造方法里初始化的,因为咱们未传入参数,默认为NonfairSync类型;
lock方法,调用sync的lock方法:
public void lock() { sync.lock(); }
无参构造方法,默认为非公平锁:
public ReentrantLock() { sync = new NonfairSync(); }
按照执行步骤,转到NonfairSync的lock方法:
接着调用: