Java中AQS的介绍及实现原理

Java中AQS的实现原理

什么是AQS

AQS全称是AbstractQueuedSynchronizer,是Java并发包中的一个基础组件,用于实现大部分的同步器实现。AQS提供了一种简单的机制来构建具有复杂同步需求的同步器,如ReentrantLock、Semaphore、CountDownLatch等都是基于AQS实现的。

AQS提供了一种FIFO队列(即同步队列)来管理线程的阻塞状态,采用CAS方法更新状态(state)的值,从而实现线程的同步机制。

AQS的实现原理

状态(state)的表示和变更

AQS中同步状态的表示是通过一个整形变量(state)来实现的,这个整形变量保存了当前同步状态的信息,如锁的占用情况,信号量的数量等。

AQS使用volatile修饰的state变量来保证线程之间的可见性,当一个线程持有锁时,它会将state设置为一个非0的整数,当释放锁时,将state重新设置为0,其他线程可以通过判断state是否为0来确定锁是否被持有。

在Java中,要想实现线程之间的互斥和同步,就需要依赖于高效稳定的同步变量,而AQS通过使用volatile关键字保证了同步变量的可见性和共享性,使用CAS(Compare and Swap)操作实现了同步变量的原子操作。

同步队列(wait queue)

在AQS中,同步状态的线程都会被加入到一个双向链表中,该链表就是同步队列。同步队列可以分为两部分:一部分是已经获得同步状态的线程,在同步队列的前面;另一部分是等待获取同步状态的线程,在同步队列的后面。

同步队列中的节点是一个FIFO队列,每个节点都包含了一个Thread类型的引用,以及用于储存等待状态的数据结构(如ConditionObject),这些节点将竞争同步状态。

当一个节点(线程)需要获取同步状态但未能成功时,它会被封装成一个Node节点,并被插入到同步队列的末尾,线程会将自己挂起。当同步状态的线程(持有锁的线程)释放同步状态时,AQS会把同步队列中的第一个节点唤醒(即运行该节点中的线程),使其再次尝试获取同步状态。

同时需要注意同步队列中每个节点的状态,例如CANCELLED表示请求被取消,CONDITION表示处于等待条件状态,SIGNAL表示需要被唤醒,PROPAGATE表示需要向下传递唤醒信号等等。AQS中对节点状态的管理十分严格,对节点的操作都需要通过CAS操作保证线程之间的同步。

同步状态具体的实现

AQS中提供了两种方式去实现同步状态,分别是独占模式和共享模式。

独占模式(exclusive mode)

独占模式下,同一时刻只能有一个线程获取到同步状态。ReentrantLock、ReentrantReadWriteLock的实现都是基于独占模式的。

在独占模式下,AQS维护了一个关于是否占用的信息,并提供了acquire(获取)、release(释放)方法来操作同步状态。通过调用上述方法,在未获取到同步状态时,线程会被阻塞挂起,直至获取到同步状态为止。

共享模式(share mode)

在共享模式下,同一时刻可以有多个线程获取到同步状态。Semaphore、CountDownLatch的实现都是基于共享模式的。

在共享模式下,AQS使用类似于信号量的机制来管理同步状态。在信号量中,同时能够被允许的线程数量是有限的,当已经达到最大并发数时,其他等待执行的线程就需要等待。AQS中也有类似的机制,它使用两个变量来描述共享状态,一个代表当前状态(state),另一个代表正在等待的线程数(waiters)。

AQS提供了两个方法用于获取共享锁:tryAcquireShared(int arg)和tryAcquireSharedNanos(int arg, long nanosTimeout),当一个线程成功获取到共享锁时,其它线程也可以获取该锁而不是被阻塞。此外,AQS还提供了对同步状态的释放以及等待队列的维护等接口,使用上非常灵活。

应用场景

AQS作为Java并发包中的基础组件,为开发人员提供了一种简单、高效、稳定的机制来构建具有复杂同步需求的同步器。下面介绍几个常见的应用场景:

ReentrantLock

ReentrantLock是一个独占锁,即同一时刻只能有一个线程获取到锁。ReentrantLock的实现就是基于AQS的独占模式,它使用了一个整形变量state来表示锁的占用情况,当锁没有被占用时,state值为0,当锁被占用时,state值为1;当锁被重入时,也就是同一个线程再次获取锁时,state值会递增。ReentrantLock中的Condition也是基于AQS的同步机制来实现的。

Semaphore

Semaphore是一种计数器,用于控制同时访问某个资源的数量。Semaphore的实现也是基于AQS的共享锁机制,可用于请求池、线程池、数据库连接池等需要控制并发访问的场合。

CountDownLatch

CountDownLatch是一个计数器,用来让一个或多个线程等待一组操作完成。在一个或多个线程调用await()方法,等待计数器变为0之前,所有线程都会被阻塞。当计数器为0时,所有在await()方法上等待的线程都会被唤醒继续执行。CountDownLatch的实现也是基于AQS的共享锁机制。

总结

AQS是Java并发包中的一个基础组件,提供了构建各种同步器的框架。AQS使用FIFO等待队列、CAS操作、volatile关键字来实现同步机制,支持独占模式和共享模式两种同步状态,具有高效、稳定、灵活等优点。了解AQS的实现原理,开发者就可以更好地利用AQS构建自己的同步器,从而更好地保证程序的并发安全。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AQS(AbstractQueuedSynchronizer)是Java用于实现同步器(如ReentrantLock、Semaphore等)的基础框架。AQS通过内部维护一个FIFO的等待队列和一个状态值,来实现对共享资源的访问控制。 AQS内部实现了两种同步模式:独占模式和共享模式。独占模式适用于只有一个线程能够访问共享资源的情况,如ReentrantLock,而共享模式适用于多个线程可以同时访问共享资源的情况,如Semaphore。 AQS的状态值代表共享资源的状态,一般情况下状态值为0代表资源未被占用,状态值为正数代表资源已经被占用,状态值为负数代表有多个线程正在等待该资源。 当一个线程请求获取共享资源时,如果资源未被占用,则该线程可以直接占用该资源,并将状态值设置为正数;如果资源已被占用,则该线程会被加入到等待队列,等待资源被释放。当一个线程释放资源时,它会唤醒等待队列的下一个线程,让其去尝试获取资源。 AQS的实现依赖于Java的LockSupport类,该类提供了阻塞和唤醒线程的功能。当一个线程被加入到等待队列时,它会被阻塞,直到被唤醒。当一个线程被唤醒时,它会尝试去获取资源,如果获取成功,则从等待队列移除,并继续执行;如果获取失败,则继续阻塞等待下一次唤醒。 总的来说,AQS通过内部维护的等待队列和状态值,实现了对共享资源的访问控制。它是Java同步器的基础框架,为实现各种同步器提供了可靠而高效的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值