队列同步器AbstractQueuedSynchronizer(AQS)是实现各种锁的关键,因此要了解锁的原理或者自己实现锁必须先了解AQS。

API

获取和修改AQS状态的几个方法

  • protected final int getState(): 获取同步状态
  • protected final void setState(int newState):设置同步状态
  • protected final boolean compareAndSetState(int expect, int update):原子的设置同步状态

第三个,原来的状态与expect相等,则修改为update状态,否则返回false

可以被重写的方法

  • protected boolean tryAcquire(int arg): 独占式获取同步状态,在此方法中需要查询当前状态并判断是否符合预期,然后CAS设置同步状态
  • protected boolean tryRelease(int arg): 独占式释放同步状态, 等待获取同步状态的线程有机会拿到同步状态
  • protected int tryAcquireShared(int arg):共享式获取同步状态,返回>=0表示获取成功,否则表示获取失败
  • protected boolean tryReleaseShared(int arg):共享式释放同步状态
  • protected boolean isHeldExclusively():当前同步器是否在独占模式下被线程占用

    AQS提供的模板方法

  • public final void acquire(int arg): 独占式获取同步状态,获取成功则返回,否则进入同步队列等待,会调用重写的tryAcquire(int arg)

  • public final void acquireInterruptibly(int arg):独占是获取同步状态,但是能响应中断,被中断抛异常
  • public final boolean tryAcquireNanos(int arg, long nanosTimeout):独占是获取同步状态,能响应中断,且有超时,超时返回false
  • public final void acquireShared(int arg):共享式获取同步状态,没获取到则进入同步队列,同一时刻可以有多个线程获取到同步状态
  • public final void acquireSharedInterruptibly(int arg):可以被中断
  • public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout):带超时,且能被中断
  • public final boolean release(int arg):独占式释放同步状态,释放后会将同步队列第一个节点唤醒
  • public final boolean releaseShared(int arg): 共享式释放同步状态;
  • public final Collection getQueuedThreads(): 获取同步队列里的线程

一些说明:

  1. 1.可以把AQS理解为管理状态的一个东西,然后你可以通过重写他的一些方法定义自己的规则
  2. 2.共享式:指几个线程可以同时获得同步状态,独占式:指只能单独的线程获得同步状态
  3. 3.方法比较多,不要怕,通过下边的例子和之后对一些锁的实现原理分析就能理解了

    AQS实现独占不可重入锁

    LockTest内部结构

    方法使用全部可以上面API部分找到
    image.png

    编写锁

    image.png

同步器编写

image.png image.png

锁的方法重写

image.png image.png

测试

  1. public static void main(String[] args) {
  2. Lock lock = new NotReentrantLock();
  3. //线程1
  4. new Thread(() -> {
  5. lock.lock();
  6. try {
  7. for (int i = 0; i < 30; i++) {
  8. System.out.println(Thread.currentThread().getName() + "--" + i);
  9. Thread.sleep(2000);
  10. }
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. } finally {
  14. lock.unlock();
  15. }
  16. }).start();
  17. new Thread(() -> {
  18. lock.lock();
  19. try {
  20. for (int i = 0; i < 30; i++) {
  21. System.out.println(Thread.currentThread().getName() + "--" + i);
  22. }
  23. } finally {
  24. lock.unlock();
  25. }
  26. }).start();
  27. }