1.类图结构

image.png

可以看到 ReentrantLock 最终还是 AQS 来实现的,并且根据参数来决定其内部是一个公平还是非公平锁,默认使用的是非公平锁
因为公平锁更消息资源,需要在内部维护一个线程的等待队列

  1. public ReentrantLock() {
  2. sync = new NonfairSync();
  3. }
  • 在这里,AQS的state值表示线程获取锁的可重入次数,在默认的情况下,state的值为0表示当前锁没有被任何线程持有,只有当一个线程第一次持有该锁的时候才会使用CAS设置state的值为1,如果CAS成功则当前线程获取锁,然后记录该锁的持有者为当前线程
  • 在该线程没有释放锁的情况下第二次获取该锁后,状态值被设置为2,这就是可重入次数(也就是获取锁的次数),在该线程释放锁的时,会去尝试使用CAS让状态值 - 1,如果 -1 后状态值为0则说明当前线程释放锁成功

2.获取锁

2.1 void lock()

  1. 在一个线程调用该方法的时候希望获取到锁,如果该锁没有被其他线程占用且当前线程之前没有获取过该锁,则当前线程获取锁,然后记录该锁的持有者为当前线程,设置state的值为1,直接返回
  2. 如果当前线程之前已经获取该锁,那就是记录可重入的次数

    1. public void lock() {
    2. sync.lock();
    3. }
  3. ReentrantLock中的lock方法委托给Sync类来实现,根据ReentrantLock构建函数来选择是公平锁还是非公平锁 ```java //NonfairSync final void lock() { //CAS设置状态值 if (compareAndSetState(0, 1))

    1. //设置当前线程为锁的持有者
    2. setExclusiveOwnerThread(Thread.currentThread());

    else

    1. //调用AQS的acquire()方法
    2. acquire(1);

    }

//FairSync final void lock() { acquire(1); }

  1. 4. 当其他线程再去尝试获取锁的时候,发现CAS失败,就去执行 acquire() 方法
  2. ```java
  3. public final void acquire(int arg) {
  4. //调用ReentrantLock重写的 tryAcquire() 方法,具体是NoFairSync或者是FairSync
  5. if (!tryAcquire(arg) &&
  6. //tryAcquire() 返回false 则将当前线程放入AQS阻塞队列中
  7. acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
  8. selfInterrupt();
  9. }
  1. AQS自己是没有提高 tryAcquire() 方法的实现的,都是子类自己去实现的

非公平锁都是抢占式的,没有先来后到的说法,任何线程都能去尝试获取锁

  1. protected final boolean tryAcquire(int acquires) {
  2. return nonfairTryAcquire(acquires);
  3. }
  4. final boolean nonfairTryAcquire(int acquires) {
  5. final Thread current = Thread.currentThread();
  6. int c = getState();
  7. //当前AQS状态值为0,说明没有线程获取到锁
  8. if (c == 0) {
  9. //CAS获取锁
  10. if (compareAndSetState(0, acquires)) {
  11. setExclusiveOwnerThread(current);
  12. return true;
  13. }
  14. }
  15. //如果是当前线程再次获取锁,则计算获取锁的次数
  16. else if (current == getExclusiveOwnerThread()) {
  17. int nextc = c + acquires;
  18. if (nextc < 0) // overflow
  19. throw new Error("Maximum lock count exceeded");
  20. setState(nextc);
  21. return true;
  22. }
  23. //返回 false 说明尝试获取锁失败
  24. return false;
  25. }

公平锁的实现

公平锁实现公平主要就是在 tryAcquire()中进行的

  1. protected final boolean tryAcquire(int acquires) {
  2. final Thread current = Thread.currentThread();
  3. int c = getState();
  4. //如果当前锁没有被其他线程持有
  5. if (c == 0) {
  6. //公平性的体现
  7. if (!hasQueuedPredecessors() &&
  8. compareAndSetState(0, acquires)) {
  9. setExclusiveOwnerThread(current);
  10. return true;
  11. }
  12. }
  13. //计算获取锁的次数
  14. else if (current == getExclusiveOwnerThread()) {
  15. int nextc = c + acquires;
  16. if (nextc < 0)
  17. throw new Error("Maximum lock count exceeded");
  18. setState(nextc);
  19. return true;
  20. }
  21. return false;
  22. }
  23. //如果当前节点有前驱节点(说明当前还轮不到当前线程获取锁)则直接返回 true,否则如果当前AQS队列为空或者当前线程节点是AQS的第一个节点则返回 false
  24. //其中 如果 h == t 说明当前队列为空,直接返回 false
  25. //如果 h != t 并且s == null 说明有一个元素将要作为AQS第一个节点入队列,返回true
  26. //如果 h != t 并且s != null 和 s.thread != Thread.currentThread() 说明队列里面的第一个元素不是当前线程,返回 true
  27. public final boolean hasQueuedPredecessors() {
  28. Node t = tail;
  29. Node h = head;
  30. Node s;
  31. return h != t &&
  32. ((s = h.next) == null || s.thread != Thread.currentThread());
  33. }

2.2 void lockInterruptibly()

该方法和lock方法的区别就是可以对中断进行响应,如果其他线程调用了当前线程的 interrupt() 方法,则当前线程会抛出 inttruptedException

  1. public void lockInterruptibly() throws InterruptedException {
  2. sync.acquireInterruptibly(1);
  3. }
  4. public final void acquireInterruptibly(int arg)
  5. throws InterruptedException {
  6. //如果当前线程被中断直接抛出异常
  7. if (Thread.interrupted())
  8. throw new InterruptedException();
  9. //尝试获取资源
  10. if (!tryAcquire(arg))
  11. //调用AQS可以被中断的方法
  12. doAcquireInterruptibly(arg);
  13. }

2.3 boolean tryLock()

尝试获取锁,如果锁没有被其他线程持有则直接获取锁,并返回true,如果锁被其他线程持有则返回false,不会导致线程阻塞

  1. public boolean tryLock() {
  2. //就是去执行一次尝试获取锁的过程
  3. return sync.nonfairTryAcquire(1);
  4. }
  5. final boolean nonfairTryAcquire(int acquires) {
  6. final Thread current = Thread.currentThread();
  7. int c = getState();
  8. if (c == 0) {
  9. if (compareAndSetState(0, acquires)) {
  10. setExclusiveOwnerThread(current);
  11. return true;
  12. }
  13. }
  14. else if (current == getExclusiveOwnerThread()) {
  15. int nextc = c + acquires;
  16. if (nextc < 0) // overflow
  17. throw new Error("Maximum lock count exceeded");
  18. setState(nextc);
  19. return true;
  20. }
  21. return false;
  22. }

2.4 boolean tryLock(long time, TimeUnit unit)

尝试获取锁,到达指定的时间没有获取到锁直接返回 false

  1. public final boolean tryAcquireNanos(int arg, long nanosTimeout)
  2. throws InterruptedException {
  3. if (Thread.interrupted())
  4. throw new InterruptedException();
  5. return tryAcquire(arg) ||
  6. doAcquireNanos(arg, nanosTimeout);
  7. }

3.释放锁

3.1 void unlock()

尝试释放锁,如果当前线程持有锁,则调用该方法会让该线程对持有的AQS状态值 - 1,如果 -1后state的值为0则释放锁,否则仅仅是 -1,如果没有持有锁而调用了该方法则会抛出异常(IllegalMonitorStateExcption)

  1. public void unlock() {
  2. sync.release(1);
  3. }
  4. //AQS
  5. public final boolean release(int arg) {
  6. if (tryRelease(arg)) {
  7. Node h = head;
  8. if (h != null && h.waitStatus != 0)
  9. unparkSuccessor(h);
  10. return true;
  11. }
  12. return false;
  13. }

核心就是 tryRelease()方法的执行

  1. //释放锁没有公平和非公平的说法
  2. protected final boolean tryRelease(int releases) {
  3. int c = getState() - releases;
  4. //如果当前线程不是持有锁的线程,则直接抛出异常
  5. if (Thread.currentThread() != getExclusiveOwnerThread())
  6. throw new IllegalMonitorStateException();
  7. boolean free = false;
  8. //计算可重入次数,如果为0则说明释放锁成功
  9. if (c == 0) {
  10. free = true;
  11. setExclusiveOwnerThread(null);
  12. }
  13. //更新状态值
  14. setState(c);
  15. //返回结果
  16. return free;
  17. }

4.小结

  1. ReentrantLock的底层就是使用AQS实现的可重入的独占锁,当状态值为0的时候表示锁为空闲的,当大于和等于1的时候说明锁已经被持有
  2. 内部默认实现的有公平锁和非公平锁,默认使用的非公平锁