1)概述

aqs全称AbstractQueuedSynchronizer【简称同步器】 ,是一个用来构建锁和同步工具的框架,ReentrantLock就是基于aqs构建的。这是一个抽象类,其子类中可以重写其中的各种同步操作方法来完成锁的实现。AQS同步器具有以下特点:
①aqs使用一个volatile修饰的原子变量state来表示锁的状态,具体代表什么状态可以由子类去定义,一般是用0代表未加锁,1代表已加锁,值得注意的是其中锁的状态的变化使用的是CAS操作;
②内部使用先进先出的队列来保存获取锁等待的线程对象,类似monitor中的EntryList;
③使用条件变量Condition 来实现等待唤醒,可以有多个条件变量,一种条件变量相当于monitor中的WaitSet;

为什么会有aqs的出现呢?在早期实现锁时一般都会使用一种同步器实现另一种同步器,因此后续jsr规范中提出aqs做统一的规范/提供统一的框架/模板,将实现锁的一些方法封装在里面,如果需要自定义锁则可以基于aqs做定制化,这也是一种模板方法模式。

自定义锁时需要重写的方法无非就是怎么获取锁怎么释放锁的操作,对应的就是对state的状态做什么样的改变。需要重写的钩子方法【一种被声明在抽象类中的方法,它可以是空方法(由子类实现),也可以是默认实现的方法】:

  1. protected boolean tryAcquire(int arg); // 获取锁的操作【独占】
  2. protected boolean tryRelease(int arg); // 释放锁的操作【独占】
  3. protected int tryAcquireShared(int arg); // 获取锁的操作【共享】
  4. protected boolean tryReleaseShared(int arg); // 释放锁的操作【共享】
  5. protected boolean isHeldExclusively(); // 检查是否是独占锁

如果需要实现独占锁就重写独占型的方法,需要共享锁就重写共享型方法,当然也可以两种都实现【读写锁】。除了上述方法,aqs类中的其他方法都是final的,无法被重写。

2)自定义锁

如果我们要实现一个自定义锁,可以先实现Lock接口(MyLock),之后定义一个内部类继承AQS(MyAQS),这里的MyAQS为锁的实现者简化了锁的实现,MyLock为锁的使用者提供了与锁交互的接口。

  1. /*
  2. * 自定义AQS独占锁
  3. */
  4. class MyLock implements Lock {
  5. /*
  6. * 静态内部类继承aqs
  7. */
  8. private static class MySync extends AbstractQueuedSynchronizer {
  9. /*
  10. * 尝试获取锁的实现
  11. */
  12. @Override
  13. protected boolean tryAcquire(int arg) {
  14. if (compareAndSetState(0, 1)) {
  15. setExclusiveOwnerThread(Thread.currentThread());
  16. return true;
  17. }
  18. return false;
  19. }
  20. /*
  21. * 尝试释放锁的实现
  22. */
  23. @Override
  24. protected boolean tryRelease(int arg) {
  25. if (Thread.currentThread() == getExclusiveOwnerThread()) {
  26. setExclusiveOwnerThread(null);
  27. setState(0);
  28. return true;
  29. } else {
  30. throw new IllegalMonitorStateException();
  31. }
  32. }
  33. /*
  34. * 是否是独占持有锁
  35. */
  36. @Override
  37. protected boolean isHeldExclusively() {
  38. return getExclusiveOwnerThread() == Thread.currentThread();
  39. }
  40. /*
  41. * 常见条件变量
  42. */
  43. public Condition newCondition() {
  44. return new ConditionObject();
  45. }
  46. }
  47. private final MySync sync = new MySync();
  48. /*
  49. * 使用静态内部类的方法来实现Lock接口中的方法
  50. */
  51. @Override
  52. public void lock() {
  53. sync.acquire(1);
  54. }
  55. @Override
  56. public void lockInterruptibly() throws InterruptedException {
  57. sync.acquireInterruptibly(1);
  58. }
  59. @Override
  60. public boolean tryLock() {
  61. return sync.tryAcquire(1);
  62. }
  63. @Override
  64. public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
  65. return sync.tryAcquireNanos(1, unit.toNanos(time));
  66. }
  67. @Override
  68. public void unlock() {
  69. sync.release(0);
  70. }
  71. @Override
  72. public Condition newCondition() {
  73. return sync.newCondition();
  74. }
  75. }

3)ReentrantLock的原理

独占锁获取锁的过程:
image-20220306225233217.png
image-20220306230818472.png