JDK源码之ReentrantLock
1.定义
ReentrantLock是一种可重入锁,允许一个线程对同一个资源重复加锁,如果说是当一个线程调用一个锁的lock()方法,然后再次调用锁的lock()方法,当锁不支持可重入时,该线程会被自己所阻塞。该锁还能支持公平锁和非公平锁的选择,公平的意思就是将锁分配给等待锁时间最长的线程,这样可以避免饥饿情况的发生,但是造成线程大量的上下文切换,影响吞吐量。
从ReentrantLock的类定义来看,该锁实现了Lock和Serializable接口。
public class ReentrantLock implements Lock, java.io.Serializable
2.ReentrantLock的具体实现
ReentrantLock通过将继承AQS的子类sync作为类成员变量来实现锁,sync实现AQS的抽象方法来管理同步状态。
(1)Sync静态内部类
//AQS的子类。 private final Sync sync; //Sync也是一个抽象类,因为锁有非公平和公平的区别。 abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; //非公平和公平锁的lock()方法有不同的实现。 abstract void lock();
//tryLock()在子类中实现,该方法是非公平的独占式获取同步状态。
//该方法首先判断同步状态是否被获取,如果没有,CAS获取同步状态并将锁的拥有者设为当前线程,如果有,判断获取锁的线程是否是当前线程,如果是,将同步值进行累加。
//成功获取锁的线程,再次获取锁,只是增加了同步值。 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; }
//获取了多少次锁,同样也要释放多少次锁。
//当同步值不为0时,还是当前线程占有锁。 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() { 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 } }
(2)NonfairSync和FairSync
ReentrantLock是支持公平锁和非公平锁的,而公平锁和非公平锁的具体实现是依靠AQS的抽象子类Sync的不同子类实现(NonfairSync和FairSync)。
//非公平锁的实现 static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; //非公平锁加锁,acquire调用tryAcquire,tryAcquire调用nonfairTryAcquire final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } //公平锁的实现 static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } //lock()调用acquire(),acquire()调用tryAcquire(),公平锁和非公平锁的tryAcquire()的实现唯一不同
//就是加入了hasQueuesPredecessors(),通过判断当前节点是否有前驱节点,如果有则当前节点不是等待时间最长的线程 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; } }
公平锁和非公平锁的主要在于两个地方:
1.获取锁lock()方法的不同:非公平锁会直接进行一次CAS,如果CAS成功,就直接获取锁了。
2.tryAcquire()方法实现的不同:当同步状态此时被释放的时候,state等于0,并没有任何线程占有锁,如果是公平锁,会判断队列中是否有线程等待获取锁,如果有的话,直接将自己构造成一个节点加入同步队列,但是非公平锁会直接CAS设置状态,不考虑同步队列中是否有其他线程等待获取锁。如果获取同步状态失败,会将自己构造成一个节点加入同步队列中,加入同步队列之后,等待前驱节点释放同步状态,唤醒自己,这后面的步骤公平锁和非公平锁是一样的。
3.ReentrantLock的主要方法
//构造函数默认是非公平锁
public ReentrantLock() { sync = new NonfairSync(); } //可选择实现公平锁 public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } //获取锁 public void lock() { sync.lock(); } //可中断式的获取锁 public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } //尝试非阻塞的获取锁,调用方法之后立马返回,能获取返回true,不能获取返回false public boolean tryLock() { return sync.nonfairTryAcquire(1); } //释放锁 public void unlock() { sync.release(1); } //获取等待通知组件,该组件和当前锁绑定 public Condition newCondition() { return sync.newCondition(); } //锁被获取的次数 public int getHoldCount() { return sync.getHoldCount(); } //锁是否被当前线程所占有 public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } //锁是否已经被获取 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(); } //查询给定线程是否在等待该锁 public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } //查询等待锁的线程数 public final int getQueueLength() { return sync.getQueueLength(); } //返回等待锁的线程集合 protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); }
4.ReentrantLock总结
聚合关系总结:
(1)ReentrantLock实现了Lock,Serializable接口
(2)ReentrantLock.Sync(内部类)继承了AQS
(3)ReentrantLock.NonfairSync和ReentrantLock.FairSync继承了ReentrantLock.Sync
(4)ReentrantLock持有ReentrantLock.Sync对象(实现锁功能)
性质:
(1)独占锁(排它锁):只能有一个线程获取锁
(2)重入锁:一个线程可以多次lock()
(3)公平/非公平锁:只针对上锁过程
(4)非公平锁:尝试获取锁,若成功立刻返回,失败则加入同步队列
(5)公平锁:直接加入同步队列