1.类图结构

可以看到 ReentrantLock 最终还是 AQS 来实现的,并且根据参数来决定其内部是一个公平还是非公平锁,默认使用的是非公平锁
因为公平锁更消息资源,需要在内部维护一个线程的等待队列
public ReentrantLock() {sync = new NonfairSync();}
- 在这里,AQS的state值表示线程获取锁的可重入次数,在默认的情况下,state的值为0表示当前锁没有被任何线程持有,只有当一个线程第一次持有该锁的时候才会使用CAS设置state的值为1,如果CAS成功则当前线程获取锁,然后记录该锁的持有者为当前线程
- 在该线程没有释放锁的情况下第二次获取该锁后,状态值被设置为2,这就是可重入次数(也就是获取锁的次数),在该线程释放锁的时,会去尝试使用CAS让状态值 - 1,如果 -1 后状态值为0则说明当前线程释放锁成功
2.获取锁
2.1 void lock()
- 在一个线程调用该方法的时候希望获取到锁,如果该锁没有被其他线程占用且当前线程之前没有获取过该锁,则当前线程获取锁,然后记录该锁的持有者为当前线程,设置state的值为1,直接返回
如果当前线程之前已经获取该锁,那就是记录可重入的次数
public void lock() {sync.lock();}
ReentrantLock中的lock方法委托给Sync类来实现,根据ReentrantLock构建函数来选择是公平锁还是非公平锁 ```java //NonfairSync final void lock() { //CAS设置状态值 if (compareAndSetState(0, 1))
//设置当前线程为锁的持有者setExclusiveOwnerThread(Thread.currentThread());
else
//调用AQS的acquire()方法acquire(1);
}
//FairSync final void lock() { acquire(1); }
4. 当其他线程再去尝试获取锁的时候,发现CAS失败,就去执行 acquire() 方法```javapublic final void acquire(int arg) {//调用ReentrantLock重写的 tryAcquire() 方法,具体是NoFairSync或者是FairSyncif (!tryAcquire(arg) &&//tryAcquire() 返回false 则将当前线程放入AQS阻塞队列中acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
- AQS自己是没有提高 tryAcquire() 方法的实现的,都是子类自己去实现的
非公平锁都是抢占式的,没有先来后到的说法,任何线程都能去尝试获取锁
protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();//当前AQS状态值为0,说明没有线程获取到锁if (c == 0) {//CAS获取锁if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}//如果是当前线程再次获取锁,则计算获取锁的次数else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}//返回 false 说明尝试获取锁失败return false;}
公平锁的实现
公平锁实现公平主要就是在 tryAcquire()中进行的
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;}//如果当前节点有前驱节点(说明当前还轮不到当前线程获取锁)则直接返回 true,否则如果当前AQS队列为空或者当前线程节点是AQS的第一个节点则返回 false//其中 如果 h == t 说明当前队列为空,直接返回 false//如果 h != t 并且s == null 说明有一个元素将要作为AQS第一个节点入队列,返回true//如果 h != t 并且s != null 和 s.thread != Thread.currentThread() 说明队列里面的第一个元素不是当前线程,返回 truepublic final boolean hasQueuedPredecessors() {Node t = tail;Node h = head;Node s;return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());}
2.2 void lockInterruptibly()
该方法和lock方法的区别就是可以对中断进行响应,如果其他线程调用了当前线程的 interrupt() 方法,则当前线程会抛出 inttruptedException
public void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}public final void acquireInterruptibly(int arg)throws InterruptedException {//如果当前线程被中断直接抛出异常if (Thread.interrupted())throw new InterruptedException();//尝试获取资源if (!tryAcquire(arg))//调用AQS可以被中断的方法doAcquireInterruptibly(arg);}
2.3 boolean tryLock()
尝试获取锁,如果锁没有被其他线程持有则直接获取锁,并返回true,如果锁被其他线程持有则返回false,不会导致线程阻塞
public boolean tryLock() {//就是去执行一次尝试获取锁的过程return sync.nonfairTryAcquire(1);}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) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
2.4 boolean tryLock(long time, TimeUnit unit)
尝试获取锁,到达指定的时间没有获取到锁直接返回 false
public final boolean tryAcquireNanos(int arg, long nanosTimeout)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();return tryAcquire(arg) ||doAcquireNanos(arg, nanosTimeout);}
3.释放锁
3.1 void unlock()
尝试释放锁,如果当前线程持有锁,则调用该方法会让该线程对持有的AQS状态值 - 1,如果 -1后state的值为0则释放锁,否则仅仅是 -1,如果没有持有锁而调用了该方法则会抛出异常(IllegalMonitorStateExcption)
public void unlock() {sync.release(1);}//AQSpublic final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;}
核心就是 tryRelease()方法的执行
//释放锁没有公平和非公平的说法protected final boolean tryRelease(int releases) {int c = getState() - releases;//如果当前线程不是持有锁的线程,则直接抛出异常if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;//计算可重入次数,如果为0则说明释放锁成功if (c == 0) {free = true;setExclusiveOwnerThread(null);}//更新状态值setState(c);//返回结果return free;}
4.小结
ReentrantLock的底层就是使用AQS实现的可重入的独占锁,当状态值为0的时候表示锁为空闲的,当大于和等于1的时候说明锁已经被持有内部默认实现的有公平锁和非公平锁,默认使用的非公平锁
