AQS继承关系

AbstractOwnableSynchronizer.png
虽然 AbstractQueuedSynchronizer 有父类,但其实父类里基本没什么东西,主要就是将 AbstractQueuedSynchronizerAbstractQueuedLongSynchronizer 关联起来,以及提供一丢丢通用的成员与方法。
AbstractQueuedLongSynchronizer 也没什么东西,其实就是一个long版本的 AbstractQueuedSynchronizer 。所以核心还是在 AbstractQueuedSynchronizer 上。
在看看子类,他们分别属于:

  • Worker:线程池(ThreadPoolExecutor)
  • Sync:可重入锁(ReentrantLock)、可重入读写锁(ReentrantReadWriteLock)、信号量(Semaphore)
  • 私有Sync:倒计数器(CountDownLatch)

再看看内部类:

  • ConditionObject:条件对象,实现Lock的基础之一
  • Node:同步队列的节点

    看看AQS的公开方法

  • void acquire(int arg)

  • void acquireInterruptibly(int arg)
  • void acquireShared(int arg)
  • void acquireSharedInterruptibly(int arg)
  • Collection getExclusiveQueuedThreads()
  • Thread getFirstQueuedThread()
  • Collection getQueuedThreads()
  • int getQueueLength()
  • Collection getSharedQueuedThreads()
  • Collection getWaitingThreads(ConditionObject condition)
  • int getWaitQueueLength(ConditionObject condition)
  • boolean hasContended()
  • boolean hasQueuedPredecessors()
  • boolean hasQueuedThreads()
  • boolean hasWaiters(ConditionObject condition)
  • boolean isQueued(Thread thread)
  • boolean owns(ConditionObject condition)
  • boolean release(int arg)
  • boolean releaseShared(int arg)
  • boolean tryAcquireNanos(int arg, long nanosTimeout)
  • boolean tryAcquireSharedNanos(int arg, long nanosTimeout)

公开方法中的核心方法就是各种acquire/release了。

看看AQS需要子类实现的方法

  • boolean tryAcquire(int arg)
  • boolean tryRelease(int arg)
  • int tryAcquireShared(int arg)
  • boolean tryReleaseShared(int arg)
  • boolean isHeldExclusively()

    分析一下ReentrantLock的Sync

    Sync重写了:

  • boolean isHeldExclusively():

  • boolean tryRelease(int releases):

它的子类NonfairSync和FairSync重写了:

  • boolean tryAcquire(int acquires):

    AQS之acquire/release

    独占模式下的acquire/release

    方法说明

    先来看一下最简单的acquire void acquire(int arg)

    Acquires in exclusive mode, ignoring interrupts. Implemented by invoking at least once tryAcquire, returning on success. Otherwise the thread is queued, possibly repeatedly blocking and unblocking, invoking tryAcquire until success. This method can be used to implement method Lock.lock. Params: arg – the acquire argument. This value is conveyed to tryAcquire but is otherwise uninterpreted and can represent anything you like.
    以独占模式获取,忽略中断。内部通过调用tryAcquire来实现,至少会调用一次tryAcquire,成功时返回。失败的话,线程会进入队列,然后不断调用tryAcquire直到成功,在这个过程中,线程可能会不断被阻塞、解除阻塞。这个方法可以用来实现Lock.lock。>
    > 参数:> arg - acquire参数。这个值会被传递个tryAcquire,且中间过程不会使用这个值,你可以将这个值设置成任何自己想要的样子。

然后看看中断模式的acquire void acquireInterruptibly(int arg)

Acquires in exclusive mode, aborting if interrupted. Implemented by first checking interrupt status, then invoking at least once tryAcquire, returning on success. Otherwise the thread is queued, possibly repeatedly blocking and unblocking, invoking tryAcquire until success or the thread is interrupted. This method can be used to implement method Lock.lockInterruptibly.

Params:

arg – the acquire argument. This value is conveyed to tryAcquire but is otherwise uninterpreted and can represent anything you like.

Throws:

InterruptedException – if the current thread is interrupted

以独占模式获取,如果中断就终止调用。内部通过调用tryAcquire来实现,先检查一下中断状态,然后至少会调用一次tryAcquire,成功时返回。失败的话,线程会进入队列,然后不断调用tryAcquire直到成功,在这个过程中,线程可能会不断被阻塞、解除阻塞。这个方法可以用来实现Lock.lock。

参数: arg - acquire参数。这个值会被传递个tryAcquire,且中间过程不会使用这个值,你可以将这个值设置成任何自己想要的样子。

再来看一下最简单的release boolean release(int arg)

Releases in exclusive mode. Implemented by unblocking one or more threads if tryRelease returns true. This method can be used to implement method Lock.unlock.

Params:

arg – the release argument. This value is conveyed to tryRelease but is otherwise uninterpreted and can represent anything you like.

Returns:

the value returned from tryRelease

在独占模式下释放。内部实现为在tryRelease返回true的时候解除一个或多个线程的阻塞。这个方法可以用于Lock.unlock。 参数: arg - release参数。这个值会被传递个tryRelease,且中间过程不会使用这个值,你可以将这个值设置成任何自己想要的样子。

返回值: 返回tryRelease的返回值

acquire流程图

acquireInterruptibly流程图

release流程图

AQS之Node

链表节点,可用于同步队列、条件队列。
成员:

  • volatile Node next:下一个链表节点
  • volatile Node prev:上一个链表节点
  • Node nextWaiter:下一个等待节点
  • volatile Thread thread:节点所代表的线程
  • volatile int waitStatus:节点的等待状态。信号通知、已取消、条件等待、传播、刚初始化

    AQS的Interruptibly系列方法

    AQS内部是使用自旋锁来实现加锁的。不带Interruptibly的方法,内部在被中断后不会返回,而是继续自旋尝试获取锁。

测试代码:

  1. /**
  2. * 该类测试ReentrantLock的lock方法阻塞线程后,在外部interrupt线程会发生什么事情
  3. * 结论是:即使interrupt了线程,lock也会阻塞到获取到锁后返回。
  4. * 所以如果需要要ReentrantLock能够响应中断,需要使用lockInterruptibly方法
  5. */
  6. public class SpinTest {
  7. public static void main(String[] args) throws InterruptedException {
  8. ReentrantLock lock = new ReentrantLock();
  9. Thread t1 = new Thread(() -> {
  10. System.out.println("t1准备请求锁");
  11. lock.lock();
  12. System.out.println("t1请求锁结束");
  13. try {
  14. Thread.sleep(5000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println("t1释放锁开始");
  19. lock.unlock();
  20. System.out.println("t1释放锁结束");
  21. });
  22. Thread t2 = new Thread(() -> {
  23. System.out.println("t2准备请求锁");
  24. lock.lock();
  25. System.out.println("t2请求锁结束");
  26. System.out.println("t2释放锁开始");
  27. lock.unlock();
  28. System.out.println("t2释放锁结束");
  29. });
  30. t1.start();
  31. Thread.sleep(100);
  32. t2.start();
  33. Thread.sleep(100);
  34. t2.interrupt();
  35. System.out.println("t2完成interrupt");
  36. }
  37. }

为什么AQS的独占模式和共享模式的标志要使用Node对象呢?

AQS的Node有两个标志成员: volatile int waitStatus;Node nextWaiter; 。前者标记等待状态(CANCELLED、SIGNAL等),后者标记是共享模式(SHARED)还是独占模式(EXCLUSIVE)。
那问题来了,为什么waitStatus使用的是int常量,而nextWaiter是Node对象呢?
这主要是为了方便重载Node的构造函数:

  1. /**
  2. * addWaiter会调用此构造函数
  3. */
  4. Node(Thread thread, Node mode) {
  5. this.nextWaiter = mode;
  6. this.thread = thread;
  7. }
  8. /**
  9. * Condition会用到此构造函数
  10. */
  11. Node(Thread thread, int waitStatus) {
  12. this.waitStatus = waitStatus;
  13. this.thread = thread;
  14. }

可以注意到,给waitStatus赋值的构造函数和给netWaiter赋值的构造函数是两个不同的构造函数。如果nextWaiter也使用int类型,那么就无法重载构造函数。