1.引子
”ReentranLock“单词中的“Reentrant”就是“重入”的意思,这是一个支持重入的排他锁,即同一个线程中可以多次获得同步状态,常表现为lock()方法的嵌套使用(类似于synchronized代码类嵌套),而在AQS类注释的使用说明中的Mutex是一个不可重入的锁,只要一个线程获得了同步状态,再次tryAcquire(int)返回false。
另外ReentranLock还支持公平锁和非公平锁的的选择,公平锁是指等待时间长的线程优先获取锁,非公平锁则对所有线程一视同仁;synchronized关键字只支持非同步锁,这是由JVM的本地C++代码决定的。
公平锁虽能解决某些线程长久等待,减少“饥饿”的发生概率,但公平锁没有非公平锁的效率高,因为它要频繁地进行线程上下文切换,一般情况下使用非公平锁。ReentranLock可以通过设置构造方法的参数来决定使用公平锁或非公平锁,其默认的无参构造方法创建的是一个非公平锁。
ReentranLock与synchronized的区别对比在以前的帖子Lock接口简介中已经说明过了,这里不再赘述。
2.类结构
由类结构图可以看出,ReentranLock类中有Sync FairSync NofairSync这三个静态内部类。Sync是一个继承于AQS的一个抽象类(AQS相关的内容在之前的帖子),它表示公平锁与非公平锁的通用或共同之处的抽象。FairSync 和NofairSync都继承自Sync,分别表示公平锁、非公平锁.它们两者的类定义差别很小,只有尝试获取锁的方法不同,FairSync使用自已定义的tryAcquire(int),而NotFairSync将tryAcquire(int)委托给父类Sync的nonfairTryAcquire(int)方法实现,而两者尝试释放锁的方法都是继承父类Sync的tryRelease(int)
扫描二维码关注公众号,回复:
9044556 查看本文章
|
ReentranLock的构造方法
ReentranLock有一个Sync类型的成员变量sync,这个成员变量在构造方法中被实例化。无参的构造方法,将sync实例化为一个NonfairSync对象,此时的ReentranLock表示一个非公平锁。带一个布尔型参数的构造方法,根据参数就会创建相应的公平锁/非公平锁。
private final Sync sync; public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * Performs {@link Lock#lock}. The main reason for subclassing * is to allow fast path for nonfair version. */ abstract void lock(); /** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ 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(); } // 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; } /** * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } }
Sync的一些其他方法
//当前线程是独占线程 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; } /** * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state }
3.可重入的实现机制
锁的可重入是指,某线程在获取到锁之后还能获取到此锁而不会被此锁给阻塞。要保证这点要解决这两个方面的问题:
1) 线程再次获取锁。当要确定当前线程是否已经获取到了锁,如果是,那么再次获取锁也必须是成功的。代码的实现:每次获取锁将AQS的state属性自增,state表示锁被线程获取到的次数。
2) 锁释放。一线程获取了n次锁,那么也需要经过n次释放,锁才能完成审美观点释放,其他线程才能获取到此锁。代码实现思路:每次释放锁让AQS的state属性自减,当state为0时,表明锁被完全释放了。
非公平锁获取锁调用的底层方法nonfairTryAcquire(int)
/** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) {//没有任何线程获取同步状态 if (compareAndSetState(0, acquires)) {//cas成功,当前线程获取同步状态成功 setExclusiveOwnerThread(current);//设置当前线程为锁的独占线程 return true; } } /** *当前线程是独占线程,即当前线程之前已经获取到了同步状态. * 进入重入处理 */ else if (current == getExclusiveOwnerThread()) { /** * nonfairTryAcquire(int)方法的被调用链上层是acquire(1),这里的acquires为1 * 相当于state自增 */ int nextc = c + acquires; if (nextc < 0) //nextc超过int类型表示的最大范围 throw new Error("Maximum lock count exceeded"); setState(nextc);//将state属性自增 return true; } return false; }
非公平锁获取锁调用的底层方法tryAcquire(int)
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { /* *与nonfairTryAcquire(int)方法相比,此处有些不同, * 只是多了"hasQueuedPredecessors()",没有前驱节点,才进行CAS更新state。 * (每个节点代表一个线程)只有在没有其他线程比当前线程等待更久的情况下才尝试获取锁 */ 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; }
公平锁和非公平锁的释放锁的方法unlock()都是调用父类Sync的tryAcquire(int)
protected final boolean tryRelease(int releases) { int c = getState() - releases;//传入的参数releases为1 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException();//当前线程不是独占线程,即当前线程没获取到同步状态,怎么能释放同步状 boolean free = false; if (c == 0) { /** * 锁当前被重复获取的次数为0,锁已经疲彻底释放了,其他线程能获取此锁了 */ free = true; setExclusiveOwnerThread(null); } setState(c);//state属性自减 return free; }
参考:《Java并发编程的艺术》方腾飞