景
ObjectMonitor() { _header = NULL; _count = 0; //记录线程获取锁的次数 _waiters = 0; _recursions = 0; //锁的重入次数 _object = NULL; _owner = NULL;//指向持有ObjectMonitor对象的线程 _WaitSet = NULL; //等待条件队列 类似AQS的ConditionObject _WaitSetLock = 0 ; _Responsible = NULL ; _succ = NULL ; _cxq = NULL ; FreeNext = NULL ; _EntryList = NULL ; //同步队列 类似AQS的CLH队列 _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; _previous_owner_tid = 0; } 从代码中可以看到synchronized实现的锁的重入依赖于JVM,JVM为每个对象的锁关联一个计数器_count和一个所有者线程_owner,当计数器为0的时候就认为锁没有被任何线程持有,当线程请求一个未被持有的锁时,JVM就记下锁的持有者,并将计数器的值设置为1,如果是同一个线程再次获取这个锁,计数器的值递增,而当线程退出时,计数器的值递减,直到计数器为0时,锁被释放。
ReentrantLock实现了在内存语义上的synchronized,固然也是支持可重入的,那么ReentrantLock是如何支持的呢,让我们以非公平锁的实现看下ReentrantLock的可重入,代码如下:
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;//只有线程全部释放才返回true setExclusiveOwnerThread(null); //同步队列的线程都可以去获取同步状态了 } setState(c); return free; } 看到这也就明白了上文说的ReentrantLock类使用AQS同步状态来保存锁重复持有的次数。当锁被一个线程获取时,ReentrantLock也会记录下当前获得锁的线程标识,以便检查是否是重复获取,以及当错误的线程试图进行解锁操作时检测是否存在非法状态异常。
2.2 获取和释放锁
如下是获取和释放锁的方法: