aqs 等待队列 同步队列,aqs同步队列与等待队列区别
00-1010AQS同步队列1、AQS介绍1.1、类图关系1.2、节点分析2、AQS实现原理2.1、队列初始化2.2、添加节点3、AQS唤醒动作
目录
AQS 同步队列
AbstractQueuedSynchronizer.的缩写是AQS,它是一个抽象的同步类,为JUC包下的大部分同步工具提供了核心实现。例如,ReentrantLock的底层使用同步队列。AQ提供了一套基本机制来实现线程同步、阻塞和唤醒、等待队列等功能。也就是说,要想深入学习线程工具,就必须掌握这个同步队列。00-1010下面是整个AQS的类结构的实现(直接从源代码打印出来的图,也可以打印出来在共同学习中观察整个程序的运行,有助于理解)。从图中,我们可以很容易地发现,Node-type拥有head和tail的双重属性。我们什么时候会接触到头尾节点的定义?每个人都是有经验的开发者,我们绝对可以把它们想象成链表。
在属性列中,我们可以看到state:int这样的状态字段。锁的重入特性就是据此实现的,可以表示当前线程的锁重入次数。整个类继承自AbstractOwnableSynchronizer类,自然对其父类中的属性有一些控制。其中thread的线程是当前持有锁的线程,在整个锁定过程中起着非常重要的作用。
00-1010当然,链表只是一种组织存储形式的数据结构。这里称之为FIFO双向队列。至于为什么是双向的,从Node的节点定义可以看出,一个节点包含prev和next节点,可以快速访问前任和后继节点。不就是典型的双向形式吗?
相信你看到这个类字段的属性名的定义,才能体会到它的作用,不过这里简单介绍一下几个字段的主要含义,以证实你的猜测。
action thread表示当前节点封装的特定线程。SHARED表示当前线程在获取共享资源时被阻塞。EXCLUSIVE表示当前线程是prev当前节点的前任节点。接下来,当前节点的后继节点。waitStatus记录当前线程的等待状态。其状态值为以下四个字段:取消取消线程信号线程需要被唤醒条件线程需要在等待传播释放共享资源时通知其他节点线程条件。
00-1010以上,我们知道AQS实际上是双向队列,如下图所示。如果线程未能获得锁,它将被封装为一个Node节点并插入到队列中。当其他线程释放锁时,它们将从队列中唤醒一个节点来竞争锁。
00-1010通过源代码可以发现,AQS初始化的时候,head和tail都没有初始化,但是这两个节点控制了整个队列,也就是说整个队列一开始都是null状态。
protected AbstractQueuedSynchronizer(){ }当第一个线程竞争锁失败时,它会被打包成一个Node,进入同步队列。这个时候就要判断了。如果当前队列为空,它将被初始化(未初始化)。初始化完成后,当前线程节点将连接到队列的尾部。
private final void initializeSyncQueue(){ Node h;if (HEAD.compareAndSet(this,(Void)null,h=new Node()){ this . tail=h;}}
从00到1010添加节点的操作是在链表末尾添加节点的简单过程,这里不再赘述。让我们看一下前面的初始化,它将向队列中添加一个额外的节点。事实上,这个节点就是已经获得锁的线程。至于为什么这样设置,你以后就明白了。
00-1010在线程唤醒的过程中,当前持有锁线程的下一个节点线程将首先被唤醒。
头指针指向下一个节点;原始头节点next指向null;当前头节点的Prev指向空;当前头节点的线程指向空。这样就完成了线程的唤醒操作,但这样做并不完美,因为AQS只是一个抽象的统一工具,本身并不规范业务,要结合ReentrantLock,CountDownLatchCyclicBarrier.等具体实现类的实现过程来分析
这就是这篇关于Java中AQS同步队列的文章。有关java AQS同步队列的更多信息,请搜索以前关于流行的它的文章或继续浏览下面的相关文章。我希望你以后能更多地支持流行音乐!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。