8

【java】j.u.c并发包 - aqs机制 | iTimeTraveler

 3 years ago
source link: https://itimetraveler.github.io/2018/07/19/%E3%80%90Java%E3%80%91J.U.C%E5%B9%B6%E5%8F%91%E5%8C%85%20-%20AQS%E6%9C%BA%E5%88%B6/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【Java】J.U.C并发包 - AQS机制

Java并发包(java.util.concurrent)中提供了很多并发工具,这其中,很多我们耳熟能详的并发工具,譬如ReentrantLock、Semaphore,CountDownLatch,CyclicBarrier,它们的实现都用到了一个共同的基类 - AbstractQueuedSynchronizer,简称AQS。AQS提供了一种原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask等等皆是基于AQS的。

同步器背后的基本思想非常简单,可以参考AQS作者 Doug Lea 的论文:The java.util.concurrent Synchronizer Framework。同步器一般包含两种方法,一种是acquire,另一种是release。

  • acquire操作阻塞调用的线程,直到同步状态允许其继续执行。
  • release操作则是改变同步状态,使得一或多个被acquire阻塞的线程继续执行。

其中acquire操作伪代码如下:

while (synchronization state does not allow acquire) {
enqueue current thread if not already queued;
possibly block current thread;
}
dequeue current thread if it was queued;

release操作伪代码如下:

update synchronization state;
if (state may permit a blocked thread to acquire)
unblock one or more queued threads;

为了实现上述操作,需要下面三个基本组件的相互协作:

  • 同步状态的原子性管理;
  • 线程的阻塞与解除阻塞;
  • 队列的管理;

AQS框架借助于两个类:Unsafe(提供CAS操作) 和 LockSupport(提供park/unpark操作)。

1. 同步状态的原子性管理

AQS类使用单个int(32位)来保存同步状态,并暴露出getStatesetState以及compareAndSet操作来读取和更新这个状态。该整数可以表现任何状态。比如, Semaphore 用它来表现剩余的许可数,ReentrantLock 用它来表现拥有它的线程已经请求了多少次锁;FutureTask 用它来表现任务的状态(尚未开始、运行、完成和取消)。

如JDK的文档中所说,使用AQS来实现一个同步器需要覆盖实现如下几个方法,并且使用getStatesetStatecompareAndSetState这几个方法来设置或者获取状态。

  • boolean tryAcquire(int arg)

  • boolean tryRelease(int arg)

  • int tryAcquireShared(int arg)

  • boolean tryReleaseShared(int arg)

  • boolean isHeldExclusively()

以上方法不需要全部实现,根据获取的锁的种类可以选择实现不同的方法,支持独占(排他)获取锁的同步器应该实现tryAcquiretryReleaseisHeldExclusively而支持共享获取的同步器应该实现tryAcquireSharedtryReleaseSharedisHeldExclusively。下面以 CountDownLatch 举例说明基于AQS实现同步器, CountDownLatch 用同步状态持有当前计数,countDown方法调用 release从而导致计数器递减;当计数器为0时,解除所有线程的等待;await调用acquire,如果计数器为0,acquire 会立即返回,否则阻塞。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK