圣诞回馈,末尾有福利,记得看完哦
1:AQS独占模式下资源的获取
在AQS中所谓的资源的获取,其实就是原子操作成员变量state从0变成1,如果操作成功,那说明就获取了共享资源,如果操作失败,说明获取资源失败,那当前线程就需要进入CLH队列等待资源的释放,然后唤醒自己再次获取资源。具体步骤如下:
2:AQS独占模式下资源的释放
独占模式下只能有一个线程拥有资源,其他线程只能等待那个线程释放资源后在去竞争。所以用完后必须把资源释放了。具体步骤如下:
3:图解独占模式下资源的获取
在有三个线程等待运行,分别是线程1、线程2、线程3,运行情况如下图:
3.1:线程1开始运行
当前只有线程1开始运行,线程2和线程3都没有运行,所以目前不存在对共享资源state的竞争,源码流程经历如下:
因为线程1直接获取到了资源,所以它不会进入CLH等待队列,目前AQS结构如图:
上面就是对AQS独占模式下资源的获取,其中牵涉到几个重要的方法:
第一个方法:tryAcquire()
这个方法需要子类去实现,它的核心思想就是对共享资源state的操作
第二个方法:addWaiter()
这个方法是获取资源失败后,加入到CLH队列的核心方法,它的第一个参数就是当前线程,它的第二个方法就是节点的模式(共享模式还是独占模式),新加入的线程会被加入到对尾,并且AQS的tail会指向这个节点
第三个方法:acquireQueued()
这个方法就是线程加入CLH队列成功后的操作,线程是继续获取资源?还是休息一会,等待被唤醒?
如果当前线程封装的节点的前驱节点是head,那这个线程就可以尝试获取资源了,但是如果资源还没有被释放,就无法获取成功,例如上面的线程2,它的前驱节点就是head,但是它获取资源失败,因为线程1还没有释放资源。获取不了资源,那线程2就休息以下,等待线程1释放资源,自己被唤醒。怎样知道要唤醒哪一个线程呢?就需要自己的前驱节点的状态waitStatus=-1,也就是SIGNAL。所以需要把前驱节点的状态改成-1.
如果前驱节点不是head,例如线程3,那么它就会像线程2一样休息以下,把线程2的waitStatus=-1,自己就可以安心的休息了,当线程2释放资源后会唤醒自己。
第四个方法:shouldParkAfterFailedAcquire()
这个方法就是将自己的前驱节点的状态变成-1,自己就可以安心的去休息了。
第五个方法:parkAndCheckInterrupt()
这个方法就是调用LockSupport的park()方法让线程挂起。
4:图解独占模式下资源的释放
我们清楚了资源的获取了,处理完逻辑后,我们必须要释放资源,否自CLH队列中的线程因无法获取资源会一直被挂起,所以资源的释放也是核心的部分,就是说我们获取了锁,必须要释放锁。
2021年马上来临,UP主给大家准备了新年礼物Java系列上述视频+源码,需要的小伙伴点赞+评论,私信“资料”无偿获取哦。