跳转至

JDK源码剖析系列之AQS

概览

AbstractQueuedSynchronizer简称AQS,采用了模板模式,是实现锁和各种同步器的模板类,提供了独占和共享两种模式。

类的主要成员

  1. volatile int state。acquire和release方法实际就是修改这个状态变量的值。一般acquire对状态值做加法,release对状态值做减法。
  2. 同步队列。实际就是一个双向链表,又叫CLH队列,一个线程获取不到共享资源的访问权限,就将这个线程打包成节点并放入这个同步队列,然后线程进入休眠。
  3. 独占线程。当前拥有共享资源访问权限的线程,主要用于独占模式判断当前线程是否拥有共享资源的访问权限。

类的api

  1. acquire 独占模式下获取共享资源的访问权
  2. acquireShared 共享模式下获取共享资源的访问权
  3. release 独占模式下释放共享资源的访问权
  4. releaseShared 共享模式下释放共享资源的访问权

这些方法都是final修饰的,符合里氏代换原则,不能被子类覆盖。在这些方法内部会调用tryAcquiretryReleasetryAcquireSharedtryReleaseShared这些模板方法,AQS中没有实现这些tryXXX方法,因此AQS的子类必须至少实现其中的一组方法(tryAcquiretryRelease是一组,tryAcquireSharedtryReleaseShared是一组)

acquire和release流程

等待队列流程

AQS除了提供了同步队列,还提供了等待队列。 用法举例:

  class BoundedBuffer<E> {
    final Lock lock = new ReentrantLock();
    final Condition notFull  = lock.newCondition(); 
    final Condition notEmpty = lock.newCondition(); 

    final Object[] items = new Object[100];
    int putptr, takeptr, count;

    public void put(E x) throws InterruptedException {
      lock.lock();
      try {
        while (count == items.length)
          notFull.await();
        items[putptr] = x;
        if (++putptr == items.length) putptr = 0;
        ++count;
        notEmpty.signal();
      } finally {
        lock.unlock();
      }
    }

    public E take() throws InterruptedException {
      lock.lock();
      try {
        while (count == 0)
          notEmpty.await();
        E x = (E) items[takeptr];
        if (++takeptr == items.length) takeptr = 0;
        --count;
        notFull.signal();
        return x;
      } finally {
        lock.unlock();
      }
    }
  }
下图解释了notFull.await()notFull.signal()的内部流程:


欢迎关注我的公众号“窗外月明”,原创技术文章第一时间推送。