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

Java锁定aqs的锁定

时间:2023-03-07 01:20:33 网络应用技术

  我相信每个人都不应该不熟悉Java的锁锁。例如,重新输入锁,锁主要用于解决线程安全问题时,当多线程操作访问共享资源。您好奇,这些锁定锁定API如何实现?本文是探索这些锁定锁定锁的方式 -实现了AQS的锁定层(Abstractqueudysynchronizer)。

  本文基于Reentrantlock。重新输入锁锁只是AQS API的呼叫。

  让我们看一下锁定的过程,首先查看源代码,然后模拟锁定两个线程的过程。

  上图是重新输入的一部分。在同步的内部类别中,有一个实例变量。该同步内部类从AQS继承。同步子类包括实现公平锁和非fair锁定。简单地说,Reentrantlock是通过同步子类的子类。

  让我们看一下Nonfairsync的Non -Flat锁的实现。

  其锁的锁定方法被重写。在实施中,由于它不公平,因此您将尝试将AQS类的状态参数更改为1通过CAS,然后直接尝试到锁定。如果您尝试锁定失败,您将调用AQS访问方法继续尝试。

  假设这里有一个线程1首先调用锁定方法,然后在此时没有人锁定,然后aqs中的变量从0更改为1通过CAS操作。线程集如图所示。。

  然后,此时还有另一个线程2可以锁定,并发现它将通过CAS操作失败,因为状态已设置为1,而线程线程2将设置为失败。在这个时间表锁定。

  当您输入获取时,您将首先致电TryAcquire,然后尝试再次锁定。实际上未实现此TryAcquire方法AQ。TryAcquire将被召唤到Nonfairsync,TryAcquire实际上将呼吁NonfairtryAcquire非fair以锁定NonfairtryAcquire Internalls class。

  首先获取锁的状态,无论锁的状态是否等于0,相当于0表示没有人锁定,您可以尝试添加它。如果您被锁定,则如果您锁定,如果您被锁定。否则是否会确定锁线是否是锁定的线程。当前线程向状态添加1个,这意味着添加了当前线程2次,即锁定的重复含义(so -so-称为可重复的是,这意味着线程可以多次获得锁定,但是只需将状态设置为MoreSecond,当螺纹多次释放时,将状态设置为0,然后将当前线程完全释放到锁定之前。

  这里的所有条件都假设它们都不建立。也就是说,当线程2试图锁定时,线程1不会释放锁,因此此方法将返回为false。

  接下来,您将转到AddWaiter方法。此方法非常重要。它是将当前线程封装到节点中,然后将此节点放入两个 - 道路链接列表中。AddWaiter首先根据指定的模式创建指定的节点。由于Reentrantlock是一个独家模式,因此传递独家将通过当前线程和模式传递。初始化了两个两个路节点节点,获取最后一个节点,并且根据是否存在最后一个节点,操作当前节点的父级。如果尾部节点不存在,您将调用ENQ以初始化

  将其放在链接列表中之后,如图所示。

  然后致电AccuireQueump方法

  一旦进入该方法,您将尝试锁定当前节点。然后,如果锁定成功,请将当前节点设置为头节点。最后,当前的线程被打断,等待唤醒。

  当线程2进来时,线程2的先前节点是头节点,但是不幸的是称呼TryAcquire方法,或者失败。

  判断当前节点的父级节点的状态,如果父级状态为-1,则意味着可以唤醒当前线程。如果取消父级状态(非现实状态是什么也就是说,Trylock方法会等待一段时间才能获取锁线并取消),然后跳过父级,找到可以唤醒的下一个父级,然后然后订阅节点关系,最后更改的状态母体级别为-1。也就是说,在将线程(节点)添加到队列之后,如果未获得锁定,则当前节点的第一个节点将设置为“睡眠前”,然后将上一个节点的waitstatus设置为-1,andIT意味着上一个节点需要在释放锁定时唤醒下一个节点。这一步骤主要是为了防止当前的休眠线程被唤醒。设置成功,将返回真实。

  接下来,您将致电Parkandchinterupt

  此方法内部调用locksupport.park方法,当前线程将睡觉。

  通过此步骤线2,由于未获得锁,它将在这里睡觉并等待唤醒。

  让我们总结锁定过程。

  线程1首先出现,发现没有人被锁定,然后在此时添加锁。此时,Thread 2过来了。在线程2锁的过程中,线程1从未发布,因此线程2不会成功锁定。不是队列,首先初始化一个),然后设置上一个节点的状态,最后通过locksupport.park方法。该线程处于休眠状态。

  如果这里有许多线程3,线程4等,那么在上一个线程2的步骤之后,这些线程将插入链接列表中,然后在链接列表之后睡觉。

  好的,在锁定过程之后,让我们看一下发布锁定的内容。

  重新输入锁的解锁实际上是一种调用AQS的发布方法。我们直接输入发布方法以查看如何实现

  输入TryRelease方法,看看同步的实现

  实际上,它非常简单,即判断锁的状态,即锁定锁几次,然后降低释放。在发布最终判断后,是锁定0的状态(因为线程可能会添加多个锁,因此必须对其进行判断),如果是的,则表示当前锁已发布,然后将所有格线程设置为null,然后返回真实。

  然后转到下一个代码。

  它是为了确定当前链接的头节点是否需要唤醒队列中的线程。如果有一个链接列表,则头节点的waitstatus绝对不是0,因为在线程休眠之前,先前的状态节点将设置为-1,并在上方锁定期间提到。

  接下来,您将转到UnparkSuccessor方法。继任者代表继承人的含义。看到名望,此方法实际上将唤醒当前线程中最近非癌的线程。

  然后,线从阻塞中醒来,并继续尝试获取锁。

  我再次发布了此代码。

  获得锁后,将头节点设置为自己。

  与我们的示例相对应,线程1释放锁后,它将在队列中线2中醒来。首先获得锁后,第一个节点(即,head节点)将从链接列表中删除节点。该方法将跳出死周期。

  此时,发布锁的过程已经完成。实际上,这很简单。当线程完全释放时,它将唤醒当前链接列表的当前节点。节点),然后觉醒节点将获取锁定,将头节点设置为自身。

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