0代码讲解Java中AQS的实现原理

21 篇文章 0 订阅

我们知道Java中的锁有SynchronizeLock,而Lock是基于队列同步器AQS(AbstractQueuedSynchronizer)实现的,今天来分析一下到底什么是AQS
这里不贴代码,只讲思想原理,代码其实很简单,原理理解了,翻翻源码就知道了

什么是锁?

首先明确一下什么是锁,所谓锁,无非就是一个独一份的共享资源,多个线程去抢这个资源,谁拿到了这个共享资源谁就持有了锁
表现在代码里形式就很多了,比如redis的分布式锁就是谁设置成功了某个固定的key,谁就持有了这个分布式锁,由于redis单线程,所以可以实现这种锁的获取方式。
而在Java的AQS里,锁的获取其实就是将AQS对象的一个voliate修饰的state属性设置成1,哪个线程成功将其设置为1,哪个线程就获取了锁。这就是AQS的锁的获取方式

AQS的实现

  1. 线程在获取锁时,如果成功获取到了锁,不用多说
  2. 如果没有获取到锁,同步器会将线程和状态信息构建成一个Node节点
  3. 将这个节点加入到同步器自身的一个队列末尾中,而同步器会持有一个指向这个队列的头部和尾部的指针。为了防止加入队列的并发冲突,同步器使用CSA的方式进行加入。
  4. 死循环(自旋)方式尝试获取锁(前提是前驱节点是头节点),如果线程能够被唤醒,线程会进入阻塞状态,否则会继续死循环尝试获取锁并尝试阻塞线程;陷入阻塞状态的线程只有前驱节点出队或者阻塞线程的中断才能唤醒
  5. 持有锁的线程在释放锁时会唤醒队列头节点的线程
  6. 被唤醒的线程会尝试获取同步状态即尝试获取锁
  7. 当持有锁的首节点线程释放锁时,会唤醒它的后继节点
  8. 后继节点唤醒后尝试获取锁(前提是前驱节点是头节点),成功后会将同步器的首节点指针指向自己(此时持有锁,不需要CAS设置),即之前的首节点脱离。
  9. 以此类推

总而言之,线程如果没有成功获取到锁,会进入同步器的同步队列中进行自旋获取锁,如果自旋没有获取锁会进入阻塞状态,阻塞的前提是成功告诉前驱节点该节点需要被唤醒,即前驱节点自身的waitStatu如果为Node.SIGNAL,则前驱节点就会在其释放锁时去唤醒后继节点,这样保证后面的节点能被唤醒:
这里就牵扯到了设置前驱节点的waitStatu,在这里如果发现前驱节点的waitStatu>0即放弃了锁的获取,则会继续向前找,找到最近的waitStatu<=0的,并将其设置为自己的前驱节点并设置waitStatu=-1SIGNAL

同步队列保证FIFO的特性,如果陷入阻塞的线程被提前唤醒,会检查自己的前驱节点是不是头节点,如果不是将不会尝试获取锁,但中断并不会将该节点移出同步队列,这个线程可能会再次陷入阻塞。

带有超时特性的

超时特性主要体现在线程阻塞上,在阻塞时会计算线程还剩下的超时时间,并阻塞这么长的时间(如果时间太短将不阻塞一直自旋,否则还不够费劲的),也就是说线程会在同步队列里待到超时为止,如果超时没获取到锁,将取消获取锁并将节点删除

独占和共享

对于独占锁,唤醒时只会唤醒头节点的一个后继节点
对于共享锁,唤醒会唤醒多个后继节点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值