一、定义

AQS全称是:AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架。框架可理解为所有工具类均要继承/实现该父类才可使用。

特点:

  • 用state属性来表示资源的状态(独占模式或共享模式),子类需要定义如何维护此状态,控制如何获取锁和释放锁;

    1. - getState:获取 state 状态;<br /> - setState:设置 state 状态;<br /> - compareAndSetState cas机制设置 state 状态。注意AQS本身是阻塞式锁,只是设置state状态时采用了cas,防止多线程同时设置state,保证线程安全;<br /> - 独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源;
  • 提供了基于FIFO的等待队列,类似Monitor的EntryList;

  • 使用条件变量来实现等待、唤醒机制,支持多个条件变量,类似于Monitor的WaitSet;

子类主要实现这样一些方法(默认抛出UnsupportedOperationException)

  • tryAcquire
  • tryRelease
  • tryAcquireShared
  • tryReleaseShared
  • isHeldExclusively

获取锁的姿势(模板):

  1. //如果获取锁失败
  2. if(!tryAcquire(arg)){
  3. //入队,可以选择阻塞当前线程
  4. }

释放锁的姿势(模板):

  1. //如果释放锁成功
  2. if(tryRelease(arg)){
  3. //让阻塞线程恢复运行
  4. }

二、应用

使用AQS实现自定义锁(不可重入锁)

  1. import java.util.concurrent.TimeUnit;
  2. import java.util.concurrent.locks.AbstractQueuedSynchronizer;
  3. import java.util.concurrent.locks.Condition;
  4. import java.util.concurrent.locks.Lock;
  5. public class TestAQS {
  6. }
  7. class MyLock implements Lock{
  8. //创建内部类,使用AQS创建锁
  9. class MySync extends AbstractQueuedSynchronizer{
  10. @Override
  11. protected boolean tryAcquire(int arg) {
  12. //cas保证操作原子性,根本上解决了线程安全问题
  13. if(compareAndSetState(0,1)){
  14. //加锁成功,设置锁的owner为当前线程
  15. setExclusiveOwnerThread(Thread.currentThread());
  16. }
  17. }
  18. @Override
  19. protected boolean tryRelease(int arg) {
  20. //取消锁的持有者,设置持有锁的线程==null
  21. setExclusiveOwnerThread(null);
  22. //设置状态为0
  23. setState(0);
  24. return true;
  25. }
  26. @Override
  27. protected boolean isHeldExclusively() {
  28. //注意这里是在判断独占锁是否被持有,而不是在判断独占锁是否被当前线程持有
  29. return getState()==1;
  30. }
  31. protected Condition newCondition(){
  32. return new ConditionObject();
  33. }
  34. }
  35. MySync mySync = new MySync();
  36. @Override //加锁,不成功会进入等待队列
  37. public void lock() {
  38. //这里调用了AQS中自带的方法,acquire是当无法获取锁时,线程进入阻塞队列等待锁,tryAcquire方法是获取不到锁则不再获取,只一次;
  39. mySync.acquire(1);
  40. }
  41. @Override //加锁,可打断
  42. public void lockInterruptibly() throws InterruptedException {
  43. mySync.acquireSharedInterruptibly(1);
  44. }
  45. @Override //尝试加锁(一次)
  46. public boolean tryLock() {
  47. return false;
  48. }
  49. @Override //尝试加锁(带超时)
  50. public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
  51. return mySync.tryAcquireNanos(1, unit.toNanos(time));
  52. }
  53. @Override //解锁
  54. public void unlock() {
  55. mySync.release(1);
  56. /*
  57. * release在释放锁后会唤醒阻塞队列中等待锁的线程
  58. * tryRelease在释放锁会并不会唤醒线程
  59. * */
  60. }
  61. @Override //创建条件变量
  62. public Condition newCondition() {
  63. return mySync.newCondition();
  64. }
  65. }

本例中,AQS的使用较为清晰。AQS可理解为一种将锁包装起来的工具类,以往线程获取锁需要先创建某一对象,然后在对象上加锁再获取锁。AQS相当于创建获得锁、释放锁等接口,将实现细节(如synchronized语句块)封装,只暴露接口给外部,以供调用。这个思想和ReentrantLock类似,ReentrantLock的实现是调用lock()与unlock()思想,也体现了封装的思想。
类中state属性用来表示锁是否被持有。一般state=0表示锁未被持有,state>0表示锁被持有;
AQS是一种阻塞式锁(悲观锁),这是由其内部实现的。具体表现为AQS的acquire方法:尝试获取锁,当无法获取锁时则会进入阻塞队列等待锁释放。

与ReenTrantLock使用方法类似,线程首先加锁、在try中实现需要加锁的代码,并在finally块中解锁;
本例中的自定义锁还是一种不可重入锁,因为lock方法调用AQS的tryAcquire方法,而tryAcquire方法的实现细节即为:cas试图将state从0改为1,可以防止锁重入

  1. import java.util.concurrent.TimeUnit;
  2. import java.util.concurrent.locks.AbstractQueuedSynchronizer;
  3. import java.util.concurrent.locks.Condition;
  4. import java.util.concurrent.locks.Lock;
  5. public class TestAQS {
  6. public static void main(String[] args) {
  7. MyLock myLock = new MyLock();
  8. new Thread(()->{
  9. myLock.lock();
  10. try {
  11. System.out.println("locking...");
  12. Thread.sleep(1000);
  13. } catch (InterruptedException e) {
  14. e.printStackTrace();
  15. } finally {
  16. myLock.unlock();
  17. }
  18. },"t1").start();
  19. new Thread(()->{
  20. myLock.lock();
  21. try {
  22. System.out.println("locking...");
  23. Thread.sleep(1000);
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. } finally {
  27. myLock.unlock();
  28. }
  29. },"t2").start();
  30. }
  31. }
  32. class MyLock implements Lock{
  33. //创建内部类,使用AQS创建锁
  34. class MySync extends AbstractQueuedSynchronizer{
  35. @Override
  36. protected boolean tryAcquire(int arg) {
  37. //cas保证操作原子性,根本上解决了线程安全问题
  38. if(compareAndSetState(0,1)){
  39. //加锁成功,设置锁的owner为当前线程
  40. setExclusiveOwnerThread(Thread.currentThread());
  41. return true;
  42. }
  43. return false;
  44. }
  45. @Override
  46. protected boolean tryRelease(int arg) {
  47. //取消锁的持有者,设置持有锁的线程==null
  48. setExclusiveOwnerThread(null);
  49. //设置状态为0
  50. setState(0);
  51. return true;
  52. }
  53. @Override
  54. protected boolean isHeldExclusively() {
  55. //注意这里是在判断独占锁是否被持有,而不是在判断独占锁是否被当前线程持有
  56. return getState()==1;
  57. }
  58. protected Condition newCondition(){
  59. return new ConditionObject();
  60. }
  61. }
  62. MySync mySync = new MySync();
  63. @Override //加锁,不成功会进入等待队列
  64. public void lock() {
  65. //这里调用了AQS中自带的方法,acquire是当无法获取锁时,线程进入阻塞队列等待锁,tryAcquire方法是获取不到锁则不再获取,只一次;
  66. mySync.acquire(1);
  67. }
  68. @Override //加锁,可打断
  69. public void lockInterruptibly() throws InterruptedException {
  70. mySync.acquireSharedInterruptibly(1);
  71. }
  72. @Override //尝试加锁(一次)
  73. public boolean tryLock() {
  74. return false;
  75. }
  76. @Override //尝试加锁(带超时)
  77. public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
  78. return mySync.tryAcquireNanos(1, unit.toNanos(time));
  79. }
  80. @Override //解锁
  81. public void unlock() {
  82. mySync.release(1);
  83. /*
  84. * release在释放锁后会唤醒阻塞队列中等待锁的线程
  85. * tryRelease在释放锁会并不会唤醒线程
  86. * */
  87. }
  88. @Override //创建条件变量
  89. public Condition newCondition() {
  90. return mySync.newCondition();
  91. }
  92. }