一、整体结构
该类位于java.util.concurrent.locks包下
首先看一下结构:
ReentrantLock中:
3个类:Sync、NonfairSync、FairSync
若干个方法:lock()、tryLock()、unlock()、acquireInterruptibly(int arg)等
具体流程
二、三个内部类
1.Sync
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; //抽象lock方法 abstract void lock(); //该TryAquire默认给非公平锁使用 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); //判断锁的状态 int c = getState(); //锁为空闲 if (c == 0) { //进行CAS操作,设置当前线程持有锁 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) { //state为0才能释放锁 free = true; setExclusiveOwnerThread(null); } setState(c); return free; } //如果当前线程同步是以独占的方式进行的,则返回true 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(); } // Methods relayed from outer class //获得占用同步状态的线程 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 } }
2.NonfairSync
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; //首先基于AQS进行CAS操作,将0->1.若成功,则获取锁成功 //否则,执行AQS的正常同步状态获取逻辑 final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
3.FairSync
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) { //比起公平锁,多了一步判断当前线程是否有前驱节点的操作 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; } }
三、主要方法
注:流程图省略了其他相关类的一些方法,只讲ReentrantLock类里面的方法,比如AQS(AbstractQueuedSynchronizer)类里面的acquere方法中省略了acquireQueued()和selfInterrupt()。
如果tryAcquire(arg)返回成功,则说明当前线程成功获取了锁(第一次获取或者重入),由取反和&&可知,整个流程到这结束,只有当前线程获取锁失败才会执行后面的判断。addWaiter(Node.EXCLUSIVE)
部分代码描述了当线程获取锁失败时如何安全的加入同步等待队列。这部分代码可以说是整个加锁流程源码的精华,充分体现了并发编程的艺术性。
1.lock()方法
1. public void lock() { 2. sync.lock(); 3. }
1.1 如果该lock是NonfairSync类的实例,则进入NonfairSync的lock()里:
最底层还是进入nonfairTryAcquire()方法里
1.2 如果该lock是FairSync类的实例,则进入FairSync的lock()里:
最底层是进入tryAcquire()方法里
2.tryLock()方法
1. public boolean tryLock() { 2. return sync.nonfairTryAcquire(1); 3. }
一步到位,直接调用nonfairTryAcquire()方法
3.unlock()方法
1. public void unlock() { 2. sync.release(1); 3. }
4.lockInterruptibly()方法
public void lockInterruptibly() throws InterruptedException { //调用父类AbstractQueuedSynchronizer里的方法 sync.acquireInterruptibly(1); } //这是父类AbstractQueuedSynchronizer的方法 public final void acquireInterruptibly(int arg) throws InterruptedException { //中断线程,如果成功中断,则抛出异常 if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) doAcquireInterruptibly(arg); }
这是Lock锁和synchronized锁相比独有的特性之一,获取锁的线程是可以被中断的,而且中断的时候抛出异常;
四、其它
由上面的图可知,ReentrantLock里面的最最基本的方法是tryAcquire()、nonfairTryAcquire()和tryRelease()
把这两个方法搞懂了,这个类也就明白很大一部分了
另外要理解两点:
1.公平锁与非公平锁的区别
FairSync中整个tryAcquire()代码只比nonfairTryAcquire()方法多了这么一行!!!
主要判断:是否有其它线程在队列的最前面。
以此来保证有序性,也就是先来后到!
这就是公平!
而不公平就是可以插队拿到锁!
2.重入锁的实现原理
1. 在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功;
2. 由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread();//获取当前线程实例 int c = getState();//获取state变量的值,即当前锁被重入的次数 if (c == 0) { //state为0,说明当前锁未被任何线程持有 if (compareAndSetState(0, acquires)) { //以cas方式获取锁 setExclusiveOwnerThread(current); //将当前线程标记为持有锁的线程 return true;//获取锁成功,非重入 } } else if (current == getExclusiveOwnerThread()) { //当前线程就是持有锁的线程,说明该锁被重入了 int nextc = c + acquires;//计算state变量要更新的值 if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc);//非同步方式更新state值 return true; //获取锁成功,重入 } return false; //走到这里说明尝试获取锁失败 }