探索Java的ReentrantLock:实现并发锁的强大力量

前言
👏作者简介:我是笑霸final,一名热爱技术的在校学生。
📝个人主页:个人主页1 || 笑霸final的主页2
📕系列专栏:java系列
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏

目录

  • 一、ReentrantLock概述
  • 二、ReentrantLock的类结构图
  • 三、ReentrantLock(非公平锁)的实现过程解析
    • 3.1加锁lock.lock();
    • 3.2 加锁失败后acquire(1)尝试获取锁
      • 3.2.1 tryAcquire()再次尝试获取锁
      • 3.2.1 addWaiter() 添加到等待队列
      • 3.2.3 acquireQueued()阻塞方法
  • 四、思维导图

一、ReentrantLock概述

ReentrantLock是一种基于AQS框架的应用实现,是JDK中的一种线程并发访问的同步手段。它具有与synchronized类似的功能,但提供了比synchronized更强大、灵活的锁机制。
特点:

  • 可重入性:与synchronized一样,ReentrantLock也支持可重入锁。这意味着同一个线程可以多次获取同一个锁,只要在每次获取锁之前都释放了之前的锁。
  • 支持公平锁和非公平锁选择:ReentrantLock可以选择使用公平锁或非公平锁。公平锁按照线程请求锁的顺序进行分配,而非公平锁不保证按照顺序分配。
  • 支持可中断获取锁:使用ReentrantLock时,可以通过调用lockInterruptibly()方法来尝试获取锁,并在等待过程中能够被中断。
  • 支持设置超时时间:通过tryLock(long timeout, TimeUnit unit)方法,可以尝试在指定的超时时间内获取锁。
  • ReentrantLock内部实现了加锁的操作,并且支持重入锁。

AQS:

  • AQS使用一个FIFO(先入先出)的等待队列来实现线程之间的协作.
  • AQS提供了一些基本的同步控制方法,如acquire()、tryAcquire()、release()等
  • AQS内部维护了一个volatile的int型变量state,这个state代表着同步状态,通过CAS(CompareAndSwap)操作来实现同步状态的获取和释放。一般情况下state的值为0或1,分别表示锁未被持有或锁已被持有 (如ReentrantLock)。但在其他的同步器中,state的值可以代表不同的含义,比如Semaphore同步器中,state的值代表着可以获取的许可数量。

二、ReentrantLock的类结构图

在这里插入图片描述

  • RenentrantLock实现了Lock接口,Lock接口提供了锁的通用api,比如加锁lock,解锁unlock等操作。
  • RenentrantLock有一个内部类 Sync而FairSync和NonfairSync继承Sync来实现非公平锁和公平锁。
  • Node也是一个内部类表示等待队列中的节点,用于存储等待获取锁的线程。

三、ReentrantLock(非公平锁)的实现过程解析

3.1加锁lock.lock();

实际上底层调用的是sync.lock();方法这里我们讲非公平锁。

 final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}

过程:
会先使用CAS改变State的值 从0到1,成功后 设置当前线程为独占线程,获取锁成功。
如果CAS失败 才会进入下面的流程 执行 acquire(1);尝试获取锁

3.2 加锁失败后acquire(1)尝试获取锁

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

可见会执行tryAcquire()addWaiter()acquireQueued()这三个方法我们来仔细看看。

3.2.1 tryAcquire()再次尝试获取锁

先看代码

protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}

进入nonfairTryAcquire

final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}

流程
先判断当前State的值是否为0

  • 进入if后 还是CAS获取锁
  • 获取锁成功 设置当前线程为独占线程 流程结束

获取锁失败
判断当前线程是否是 独占线程(可重入实现原理

  • 是当前线程 State+1 标记获取锁的次数 返回 true
  • 不是当前线程 就跳过当前if 直接返回 false

3.2.1 addWaiter() 添加到等待队列

注意
如果上一步返回为true 就不会执行此方法

 private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failureNode pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;}

可见 第一次 tail就是为null 不会进入if 而是先 enq(node);去创建队列
非第一次 就会CAS操作把当前节点设置为尾节点 成功入队 返回node 然后执行 acquireQueued()方法

看看enq(node)如何创建队列

private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}

fo循环
先通过CAS创建队列 并设置头节点
然后第二次for循环 通过CAS入队 成功返回当前节点也 执行 acquireQueued()方法

3.2.3 acquireQueued()阻塞方法

final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}

也是for循环

  • final Node p = node.predecessor();获取当前队列头节点 如果当前是头节点又会执行tryAcquire(arg)获取锁
  • 如果获取锁失败 或者不是头节点 就会执行下面的if

shouldParkAfterFailedAcquire(p, node)

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {int ws = pred.waitStatus;if (ws == Node.SIGNAL)/** This node has already set status asking a release* to signal it, so it can safely park.*/return true;if (ws > 0) {/** Predecessor was cancelled. Skip over predecessors and* indicate retry.*/do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;} else {/** waitStatus must be 0 or PROPAGATE.  Indicate that we* need a signal, but don't park yet.  Caller will need to* retry to make sure it cannot acquire before parking.*/compareAndSetWaitStatus(pred, ws, Node.SIGNAL);}return false;}
  • 先获取 当前 waitStatus 字段用于表示节点在等待队列中的状态。
    用来比对当前置节点的状态 结合外层for循环 进入 compareAndSetWaitStatusCAS操作前置节点的状态设置为 -1(waitStatus=-1
  • 最后调用 LockSupport.park(this);阻塞当前线程

四、思维导图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1620933.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

苹果基带坏了怎么办_iPhone12 上市,苹果这次有哪些改变

苹果每年一度发布新品时间一般在9月份 但今年疫情使得发布延后&#xff0c;这里对iPhone12网上流传的配置做下总结 通讯方面: 这次毫无疑问的事iPhone12从之前的4G升级到了5G&#xff0c;使用高通X55基带&#xff0c;这次再也没用英特尔的基带了&#xff0c;英特尔基带手机信号…

iPhone12基带确认,果粉放心

在iPhone12发布的时候都没有提到iPhone12到底用的是什么基带&#xff0c;我之前在粉丝留言下方说了是高通基带&#xff0c;我当时说可能部分手机是因特尔部分是高通&#xff0c;今天有人在社交媒体发布了iPhone12的基带从中可以看出本次iPhone12采用的是高通的X55基带&#xff…

android备份基带,备份过SHSH,保留基带,直刷5.0.1系统完美详细教程

此教程仅适用于备份SHSH直刷任何高于现手机版本的任何系统&#xff0c;我的系统是4.3.3直刷到5.0.1.可能刷法不同&#xff0c;我的用电量貌似没有增加&#xff0c;依然比较省电,没有大家说的掉电突然增加的现象。而且&#xff0c;刷完5.0.1&#xff0c;我的3G开关也依然存在&am…

苹果或方案自立研制iPhone基带芯片

据业界人士称&#xff0c;苹果方案组成一支新的研制团队去开发基带处理器&#xff0c;那些基带处理器将被用于它方案在2015年发布的新款iPhone中。知情人士还说&#xff0c;苹果方案将基带芯片的订单交给三星电子和Globalfoundries。 尽管某些知情人士还说&#xff0c;苹果或许…

使用Easy Chm制作chm文档步骤

前言 软件发布后需要相应的文档说明&#xff0c;CHM是微软新一代的帮助文件格式&#xff0c;利用HTML作源文&#xff0c;把帮助内容以类似数据库的形式编译储存。因为使用方便&#xff0c;形式多样也常被采用作为电子书的格式&#xff1b; 制作类似的chm文档可以使用Easy Chm软…

JWT 技术的使用

应用场景&#xff1a;访问某些页面&#xff0c;需要用户进行登录&#xff0c;那我们如何知道用户有没有登录呢&#xff0c;这时我们就可以使用jwt技术。用户输入的账号和密码正确的情况下&#xff0c;后端根据用户的唯一id生成一个独一无二的token&#xff0c;并返回给前端&…

bindService的调用流程

使用bindService去调用service&#xff0c;如果有多个客户端调用&#xff0c;onBind方法只会被调用一次&#xff0c;由于bindService嗲处理中&#xff0c;AMS是一个中间商&#xff0c;猜测这个处理也是AMS里进行的&#xff0c;这里我们再看看bindService的调用流程 public clas…

【翻译】开发人员的技术写作

HTML、CSS、JavaScript、Python、PHP、C、Dart--有这么多的编程语言&#xff0c;你甚至可能完全精通其中的几种但是&#xff0c;当我们的目标是写出更多、更好的代码时&#xff0c;我们用日常语言写作和交流的方式变得越来越重要......甚至可能被忽略了。 我们写代码和围绕代码…

AIGC用于智能写作的技术综述-达观数据

导语 图1. ChatGPT生成的关于智能写作的介绍 智能写作指使用自然语言处理技术来自动生成文本内容。这种技术通过分析给定语料库&#xff0c;学习文本的结构和语法&#xff0c;然后利用这些信息来生成新的文本。智能写作可以用来快速生成高质量的文本内容&#xff0c;并且可…

玩转ChatGPT:论文辅助写作(附Claude测评)

一、写在前面 嘿&#xff01;嘿&#xff01;嘿&#xff01;大家好&#xff0c;今天我们来聊一下使用GPT们进行论文辅助写作。不过&#xff0c;我要先交代一下&#xff0c;GPT的使用门槛比较高&#xff0c;不少童鞋都用不上。所以&#xff0c;我极力推荐一个平替产品——Claude…

帮你的英文写作一键纠错,微软升级版AI批改软件有这些亮点

你的英语还好吗&#xff1f; 学英语时&#xff0c;“听说读写”是四大核心要素&#xff0c; 而“写”可谓是英语学习中最考验学习者综合语言运用能力的一项。 在写作的时候&#xff0c;你会面临写错、单词匮乏以及语法错误等诸多问题&#xff0c;但如果让你自己或者找别人修改…

系统集成项目管理工程师【中级】考证学习资料知识点整理分享——第二章《信息系统集成及服务管理》,持续更新中........

系统集成项目管理工程师(中级)考证学习资料整理分享,持续更新中........ 目 录 第二章《信息系统集成及服务管理》 一、信息系统集成及服务管理 (一)信息系统集成及服务管理的内容 (二)信息系统集成及服务管理的推进 1.实施信息系统集成及服务资质管理制度 1)…

webassembly003 ggml GGML Tensor Library part-3

关于pthread_create()和pthread_join() #include <stdio.h> #include <pthread.h>void *thread_func(void *arg) {int *num (int *)arg;printf("Hello from thread! arg%d\n", *num);pthread_exit(NULL); }int main() {pthread_t thread;int arg 10;i…

数据结构--树4.2(二叉树)

目录 一、二叉树的定义和特点 1、定义 2、特点 二、二叉树的基本形态 1、空二叉树 2、只有一个根结点 3、根结点只有左子树 4、根结点只有右子树 5、根结点既有左子树又有右子树 6、斜树 7、满二叉树 8、满二叉树和完全二叉树 三、二叉树的性质 一、二叉树的定义和…

Presto之Driver个数

一. 前言 在Presto的Stage Performace中&#xff0c;每个Operator中都会有Driver个数的显示&#xff0c;如下图所示。本文主要介绍Presto中是如何决定Driver的个数的。 二. Driver个数 在Presto中&#xff0c;一个pipeline中启动多少个Driver&#xff0c;是由此Pipeline处理的S…

新增收货地址【项目 商城】

新增收货地址【项目 商城】 新增收货地址1 新增收货地址-数据表创建2 新增收货地址-创建实体类3 新增收货地址-持久层3.1 各功能的开发顺序3.2 规划需要执行的SQL语句3.3 接口与抽象方法3.4 配置SQL映射 测试4 新增收货地址-业务层4.1 规划异常4.2 接口与抽象方法 测试5 新增收…

epoll() 多路复用 和 两种工作模式

1.epoll API 介绍 typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64; } epoll_data_t;struct epoll_event {uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */ };常见的Epoll检测事件&#xff1a;- EPOLLIN- EPOLLOUT- …

农村农产品信息展示网站的设计与实现(论文+源码)_kaic

摘 要 随着软件技术的迅速发展,农产品信息展示的平台越来越多,传统的农产品显示方法将被计算机图形技术取代。这种网站技术主要把农产品的描述、农产品价格、农产品图片等内容&#xff0c;通过计算机网络的开发技术&#xff0c;在互联网上进行展示&#xff0c;然后通过计算机网…

如何识别计算机病毒,怎样识别计算机病毒

电脑病毒不仅影响电脑的正常使用&#xff0c;有时候还会威胁到我们的个人信息包括财务信息的安全。下面就让学习啦小编教大家怎样识别计算机病毒吧。 识别计算机病毒的方法 病毒一般通过自我隐藏的方式来达到自己的目的&#xff0c;那么病毒一般都隐藏在系统的什么地方呢?一般…

计算机病毒为了隐藏,识别计算机病毒的方法

识别计算机病毒的方法 病毒为了能随系统启动而自启动对电脑进行危害操作&#xff0c;通常会把自己设置为自动启动。更有甚者&#xff0c;它们还会将自己注册成系统服务&#xff0c;优先于其他程序启动。下面是小编收集整理的识别计算机病毒的方法&#xff0c;欢迎阅读。 识别计…