当前位置: 首页 > 网络应用技术

AQS的未知细节

时间:2023-03-07 11:27:33 网络应用技术

  大家好,我是Axuan。

  让我们分析今天AQS的源代码。

  说到AQS,我们的第一个反应是重新进入,倒计时,信号量等。它们都是根据AQS实施的。

  互联网上有很多有关原理和机制的文章。今天不是我们的重点。本文主要分析源代码。

  在开始分析源代码之前,我们可以简要审查AQ。

  使用AQS,并由常规方法本身实现,并将自定义方法移交给不同的继承。如果我们自己写一个,我们只需要实现最高级别即可。

  只需总结AQ。有了一个可变控件,他将自己收拾成一个,排成一个,也称为一个,然后挂断醒来以继续锁定。锁定锁的线也可以暂时释放锁并输入一个,也就是说等待唤醒 - 然后再次输入。

  同步队列和等待队列之间的区别在于,一个是。

  我们已经完成了原理部分,我们开始输入源代码分析。图案我们主要分析锁,解锁,条件等待和觉醒的源代码,该版本基于JDK1.8。

  没什么可说的,我们开始了。

  为了整个过程的完整性,我们从一开始就选择了一个AQS实现类。

  首先,重新输入lock呼叫方法开始锁定。调用了内部类别的内部类别的锁定方法。该类继承AQS,锁定方法是一个。

  他有2个子类,我们首先研究了Nonfairsync的实施

  首先尝试设置,也就是说,如果失败方法失败。LET查看Fairsync的实现

  从中,我们可以看到,非亲密和公平是非事物的,无论三个七个二十一个,公平是诚实地称呼该方法。

  获取方法是AQS方法。

  我们可以在这里看到的方式,每个子类的方法将根据不同的实现功能实现,因此将此方法提供给子类以实现自身,而该方法是AQS实现自身。

  输入该方法,我们主要查看实现方法,请按照源代码进行操作,最后介绍该方法

  此方法非常简单。首先获取变量。如果是0,则意味着它将被赶回返回。如果状态不是0,则可以判断持有锁定的线是否为本身。如果将其添加到状态,我们可以从这里看到重新进入锁定锁定是肯定的。如果以上两种情况不是,则锁会失败并返回false。

  我们上面已经说过,锁故障将进入同步队列,因此他将调用进入队列的方法

  第一个包装一个节点,然后确定它是否为空。

  如果我们让我们在这里写作,则估计它是一种直接的方法。不会有判断。当我们查看ENQ方法时,我们会发现它实际上是一个其他操作。否则的内容与此处的IF完全相同。

  这样的写作有什么好处?

  这是控制大个子的能力。由于初始化,后来的线程只是在排队等候。如果您直接使用该方法,则必须每次对ENQ方法中的判断进行判断,但似乎可以看出,尽管在表现方面的改进方面很小,但是将力量拉下,这不符合符合大个子的风格。

  实际上,初始化中有一个隐藏在这里。我们只是谈论非flat锁定方法。

  相比之下,可以发现判断和这种方法中存在条件。

  由于这是一个公平的锁,因此如果您不能出现,它一定不能锁定,因此必须确定下一个队列中是否有节点。如果是这样,请不要抓住它。

  此方法是确定队列中是否有节点。第一个条件,我们都知道aqs同步队列中的第一个节点是只有一个属性,第二个节点,因此,如果有一个节点等待,则头是头,然后头是头,头是头,然后头是头。节点绝对不等于尾部节点。

  接下来的两个条件是连接的。只要建立一个,就意味着有节点在等待。第一个。当您看到这种情况时,有人可能会想知道。如果第一个节点的下一个节点是空的,那么有一个节点?对于空,队列只有一个头节点吗?如果只有一个节点,则应该相等,为什么?

  原因是我们刚才说的地方,让我们仔细观察该代码。

  设置在此处设置,然后设置不可用。也就是说,它将发生。设置设置后,情况仍然存在。尽管这种状态仍然存在,但仍然存在,但事实就是这样。尽管他仍然在那里,但表明已经有节点了。

  第二个条件是当前的等待线程不是您自己。这是理解的。

  好的,然后向下看,之后,下一个是队列中的节点,输入方法

  这种方法是要锁定,让我们仔细看一下。

  首先,这是一个。首先,确定当前节点的第一个节点是否为。如果您尝试抓住锁,则可能会在此时发布锁的线程。我不会在此处详细介绍。

  如果抓住它,则将其设置为自己,将上一个头节点的下一个节点设置为null,并将变量设置为false,表明没有故障。该变量用于中断后取消节点,将在后面提及。最后,返回,然后输入您编写的业务代码,以便在锁后开始逻辑。

  如果您不抓住它,请先输入

  该方法的目的是将先前的节点设置为waitstatus,并简单地查看此变量值的范围

  总共有5个值,1代表-1代表-2表示-3表示还有另一个。

  第一个判断,这只是我的含义,直接返回。

  第二个判断表示先前的节点,然后循环循环直到找到第一个无关节点,返回false,然后再次在外层输入此方法。设置成功后,它们再次进入外层。层。这次,我终于回到了真。

  现在,将上一个节点的状态设置为告诉上一个节点的含义。如果您结束它,请记住将我放在接下来,我会开始假装,不,开始睡觉。

  输入方法

  如果您什么也没说,直接。

  在这里,发生了什么事,我们稍后会说。

  首先回到外层,每个人都注意到,这里有一个代码块来处理取消节点。

  Axuan当时想到,这种方法如何进入?

  似乎只有一种情况,也就是说,当线程没有获得锁时,Axuan开始发现异常。在整个方法中,将有两个地方。

  如果先前的节点被抛出,武当长期以来的想法,并且会在没有任何情况的情况下发生这种情况。可能要谨慎。

  返回先前的节点,或者如果null,则抛出NullPoInterException。使用前身插座时使用。NULL检查核心为EL,但在场以帮助VM。

  注意这个词,省略

  另一个在方法中

  它将出现在超过时,但这与中断无关。

  因此,阿克西亚(Axuan)非常困惑。如何在唤醒线程中断后取消获得锁定的方法。是否中断,没有中断?

  因此,我只能寻求帮助www.baidu.com。正如Axuan认为,这种问题基本上是百度。无助,我只能在世界上最大的同性约会社区中寻求帮助。

  Axuan搜寻了很长时间,没有找到与他自己类似的问题。

  很快,11分钟后,有人回答

  第一句话是欢迎使用Stackoverflow,因为stackoverflow可用于新移民,因此可以看到。可以看出,外国人对新移民仍然非常好。Xuan静静地瞥了一眼此人的个人资料。

  Jungleegames,该公司的首席工程师

  也许Axuan是第一次问这个问题。这个问题非常清楚地描述了它。他说他希望我能提供更多信息。我不知道我想问什么。这很尴尬。再次

  不要以为Axuan的英语很好。他们都是中国人,然后翻译成英文。可以在这里看到它的重要性。有时,翻译软件不是很准确,哈哈,远。

  在这段时间里,一个武士一直在反复思考原因,最终在突然开朗时无意中瞥了一眼。

  以排队的线程为单位以排他性的方式获取。通过条件等待方法用作接受。

  不要首先查看整个段落的含义,请注意单词。

  此评论被翻译。对于已经在队列中的节点,要获取锁,这意味着。因此,有时源代码的注释非常重要,请好看。

  从那时起,它就无法中断,必须有一种打断的方法。

  因此,一个Xuan寻找它,并肯定地提供3种方法来获取锁

  这三种方法的一般过程几乎相同,唯一的区别是稍后处理

  第一种方法是中断状态,但是后两个方法是

  在这一点上,Axuan的怀疑终于终于。对于已经在队列中的节点,如果您要他取消获得锁定,则在接下来的两种方法中调用两个方法,否则您将使用第一个方法。

  现在,让我们谈谈我刚才提到的事情。

  它是什么?

  当Xuan首先读取此源代码时,为了找出线程之后的过程,添加了和谐的源代码,并

  然后我写了一个测试程序

  这意味着什么?

  它是锁定锁后3000秒首先,然后是3个线程,然后是3个线程2。

  正常运行时,结果就是这样

  但是,如果我在这里添加一个可以再次运行

  发生了什么事

  线唤醒后

  武士首次惊呆了。发生了什么事,模型中是否存在?

  然后,Xuan将测试程序中的中断更改为方法,结果仅打印一次,结果与正常操作相同。

  然后问题就在其中。

  目前,我只能寻求帮助以再次建立约会社区,所以Axuan问了另一个问题

  这次42分钟后,有人回答了一个Xuan。他问我在哪里,然后阿克斯安再次解释了。在此期间,我看到了大个子的简短介绍,发现这是英文英语的中文,中文和中文。在这里的交流中,我感到很奇怪。Xuanguo问大个子的微信,想添加微信私下说话,但这个大家伙忽略了一个Xuan,有点尴尬。

  他说,之后,我立即写下了您的问题,我将花时间学习他,然后再学习他。

  一个多小时后,他回答说,他说他,然后Axuan点击了一下,看了看它

  看来大个子不知道问题在哪里

  三个小时后,有人回答

  这个人的答案没有说明,但他提到了一个字,这是什么意思,

  我相信您或多或少听到了这个词,感觉很像

  对于一个受欢迎的例子,这是什么意思:如果有3个线程A,B,C,A和B在中间等待。。

  考虑到这一点,一个Xuan立即去看了该方法

  果然,在评论中,作者还说,连接线程将是第一个,称为觉醒,第二个,唤醒,第三个是,作者还解释说没有理由。

  线索在这里,您只能开始。

  然后,Axuan在Stackoverflow上观看了有关所有问题的所有问题。

  事实证明,越头晕,越头晕,(哭泣),这可能是Axuan的水平,我真的不明白大家在说什么

  最后,Axuan在源代码下没有秘密,只能看到它。

  源代码中总共有判断。

  让我们简要介绍实施机制,JVM和两个变量。

  他只有柜台的含义将他设置为1,将他设置为0,多次致电Unpark,柜台不变。这就是为什么命令写错了,但是Park and undark却不会,因为即使您即使您首先打开标记,将计数器设置为1,然后当打电话给公园时,您会发现柜台是1.而不是。这是图片在投标中的位置。

  这是锁定,当扩展扩展时,这是底层,因为计数器也存在,因此需要进行锁定保护。

  在这里说话,让我们看一下特定的源代码,首先查看2个参数,这两个参数指出,如果您设置了它,则称为aqs

  它被传递给。

  让我们看看①判断,此功能实际上是什么意思。如果是1,则将他设置为0,然后返回。

  ②判断当前线程,如果被中断,则返回。请注意第二个参数,此参数表示含义,中间源代码如下

  这意味着,如果调用此方法,他将返回当前线程,然后将参数删除。

  如果线程中断,则第一个呼叫将返回true,第二个呼叫将返回false。

  这不是中断徽标。

  ③和④是时间,这是0,它不会到来。

  然后来到这种方法,这是真正的地方。

  ⑤仍然先判断,然后尝试获取锁。

  ⑥确定计数器是否为1,设置为0到1,然后。

  阅读公园方法后,让我们再次看一下该方法

  该方法主要是要做2件事,首先设置为true,然后调用该方法,然后查看Unvark

  Undark还主要做了两件事,主要将其设置为1,然后调用该方法以唤醒悬挂线。

  现在,我们将串起整个过程并再次运行。

  首先,该线程悬挂在公园方法中,然后中断以判断其是否被中断。是的,返回,然后调用源代码清除。

  然后,穿过外层并再次进入方法,因为此时,设置设置为0,返回,然后从外层循环。它不满足。再次挂断,打印两次。

  什么?打印两次?

  在状态上是正确的,正常运行是错误的?

  Axuan几乎是

  站在窗户的侧面,会冷静下来。

  是的,我的操作系统是,我看到了什么?

  从这里我们可以看到源代码的基本实现被分配

  所以快点看

  可以看出,它主要分为分为多,中间没有变量。①主要判断时间。根据我们的传记错误和0,它将到达第二个分支。然后输入第一张法官的判决,如果返回,否则将被悬挂。

  看看Untark

  老实说,我不太了解,猜测应该是。

  好吧,如果它根据源代码,它将仅打印一次。

  但是,仍然无法解释为什么它将被打印2次。

  最后,一个Xuan拥抱了所有情况并贯穿了所有情况,并将该程序放在Centos8机器上的Alibaba Cloud上的机器上。结果仍然只是。

  在这一点上,Axuan具有完全侵略性。

  当他写这篇文章时,一个武士没有想到为什么要印刷两次。如果有些读者和朋友知道,欢迎添加Xuan的微信信号,并私下告诉Axuan。

  好的,我上面已经谈论了很多,我觉得本文的标题应该更改为眼泪

  下一件事我们要查看的最后一个方法是打断后打电话的方法

  一般过程非常清楚,首先将其设置为null,毕竟,从当前节点开始,所有取消节点,直到找到第一个节点,然后指针指向他。请注意,这里没有找到以前的节点。

  然后将节点状态设置为

  然后,判断当前节点是否是(如果是),请尝试将找到的节点指向尾部节点并指向它。

  否则,判断您发现的节点是否是尝试将其设置设置为-1,并判断他的线程不是空的。

  在这里考虑一些问题。

  如果您的下一个节点是,为什么不继续呢?

  实际上,原因也很简单。如果下一个节点被取消节点,则他还将查看它是否是取消节点,因此下一个节点是或到目前为止的。

  来思考一个问题

  如果同时发生什么,会有问题吗?

  例如,为了简化,仅在图片中绘制指针,并且省略了指针

  现在,取消了4和6个节点。根据源代码逻辑,他们将将设置设置为3个节点,然后运行到状态判断

  这3个节点也会发生,并将其判断之前设置为1个节点,然后4和6个节点将进入分支,执行方法和3个节点成功通过了判断

  但是因为他的下一个节点已经

  如果判断失败了,我什么也不会做,并指出了我自己

  让我们看看我们将在输入4和6进入的方式中做什么

  由于节点已经输入,因此您发现的内容,您发现的内容,也就是说,N节点的第一个节点是本身或其他取消节点,然后是该节点。

  觉醒后,我们将进入我们之前提到的。周期之后,我将来到这种方法,并记住,因为他的先前节点是取消节点

  所以我会来

  在这里,节点将从您自己开始,找到未解决的节点,然后互相设置

  早些时候,我们提到我们同时唤醒多个节点,然后在这里,多个节点,每个节点将负责距离,不要互相干扰,请重新构建一个新的链接列表以滤除取消节点。这有点像以前所说的多线程协调扩展。

  好吧,回到我们刚才说的话

  想一想这样一个问题,为什么这种遍历?

  Axuan认为,第一点是在上一个方法中

  指针仅在这里设置,并且没有设置。

  第二点记得,是吗?

  他在设置之前先设置为首先设置,因此可能是最新的节点。

  因此,它用于从后面穿越,而不是从后面穿越。

  此时,分析了锁的源代码,让我们看看下面

  入口仍然来自重新进入,AQS称为

  该方法也被授予子类以实现

  在这里,判断未锁定的线程是否是线程,而不是异常。

  然后判断发行版是否等于0,因为它已完全释放以返回true,否则是错误的。

  如果队列中有一些节点,则调用该方法,此方法刚刚说过,因此我不会详细介绍。

  可以看出,解锁仍然很简单,让我们看下面的等待队列

  进来确定它是否被中断。

  然后加入等待队列,调用方法

  这是一个简单的团队操作。有两个地方需要注意。

  此方法实际上可以演变为算法:给您一个,每个节点都有一个属性,使您可以删除不等于链接列表的节点以形成一个新的链接列表。

  这是纯链接列表的操作,所以我不会谈论它。

  要注意的另一件事是,等待队列的节点只是指针,没有指针。

  然后下去

  它将在此处重置为0,然后调用觉醒的头节点的下一个节点。

  然后来到该方法中最关键的部分,一个,周期的状况是

  该方法的作用是确定当前节点是否仍在中间。

  首先,如果节点等于,则肯定会消失,因为同步队列的节点不等于null。此时

  那么为什么这两个判断?

  第二个不是零,如果不是零,则必须在同步队列中。

  最后一个,呼叫方法

  此方法是使同步队列一次来看看您是否不在那里,简单而粗鲁。

  如果确定不再同步队列,则意味着等待队列已到达,然后将调用线程。

  在这里考虑一个问题。如果您更换,可以吗?

  还记得我们之前所说的话,线程悬挂后有几种方法吗?

  回顾,有3种类型

  因此,如果在这里发生,如果使用它,则该程序将继续在下面运行,那么将会发生一些问题。

  因此,即使您不小心唤醒了您,也可以使用它的方法是使用它,但是您仍然会再次陷入

  存在这里,这是一种查看方法的方法

  如果是这样,请返回0。

  有些朋友可能不得不问,难道不再悬挂再次进入周期吗?

  不,您将其设置为0,稍后会看到它。

  让我们看看如果有中断,进入的方式会发生什么

  首先设置为0,然后输入同步队列并返回true。

  在这里,一些读者和朋友可能会有疑问。在什么情况下?

  是的,想象一下这种情况,另一个线程首先唤醒线程,然后还有另一个线程可以放置线程。目前,它已将其设置为0,然后设置将失败。

  然后进入以下内容,因为节点将转移到同步队列,因此我们将判断它是否已经存在。目前,我们刚刚说的两个看似没有用的条件将扮演角色。LET等待一会儿,然后在转会后返回虚假。

  这里有2个变量

  1表示需要-1表示需要。

  如果首先醒来然后中断,则返回1,首先中断,然后信号返回-1。

  然后,如果未建立if条件,请跳出周期。

  然后进入我之前说过的方法。要注意这里的一件事是,如果是这样,但是由于该方法已返回到锁中,因此您需要将其设置为1才能让他。

  然后判断,如果是这样,它将被放置为无效,但是如果是这样,他将把后来的链条带到同步队列,因此您需要在这里等待队列。

  终于来了,判断是还是

  等待完成,让我们看看最终的方法

  如果不是线程呼叫,则持有锁定。

  如果有节点在等待队列,他

  如果只有一个等待节点,请将其设置为第一个等待节点到null。

  然后调用方法开始

  这里还有一个问题。

  如果是这样,请返回false,如果等待队列的第二个节点不是null,请开始。

  如果呼叫进入,如果先前的节点是或以后的,则将其唤醒,然后倒下。

  因此,不一定是呼叫方法。如果一切正常,他将不会成为释放头节点锁定的第一个节点。

  本文付费进行分析的地方。可以看出,作者是交织在一起的。如果我们编写它,则估计会有很多代码,不一定是正确的。

  因此,当您没事的时候,学习大个子并思考更多。从长远来看,代码级别肯定会确保。

  原始:https://juejin.cn/post/7098161423544483847