京东二面:Sychronized的锁升级过程是怎样的

news2024/11/19 16:31:43

引言

Java作为主流的面向对象编程语言,提供了丰富的并发工具来帮助开发者解决多线程环境下的数据一致性问题。其中,内置的关键字"Synchronized"扮演了至关重要的角色,它能够确保在同一时刻只有一个线程访问特定代码块或方法,从而有效地防止数据竞争和保持内存可见性。

在传统的Synchronized实现中,由于其采用的是重量级锁机制,每次获取和释放锁都涉及操作系统层面的线程调度,这无疑增加了线程上下文切换的开销,尤其在高并发且锁竞争较小的场景下,可能会导致不必要的性能损失。为此,从Java 6开始,JVM引入了锁升级机制,这是一种动态调整锁状态的技术,旨在根据不同场景灵活运用不同级别的锁,从而在保证并发安全性的同时,最大程度地提升程序的运行效率。

关于Synchronized的实现原理,请参考:美团一面:说说synchronized的实现原理?问麻了。。。。

本文将深入探讨"Synchronized"的锁升级过程,详细介绍从无锁状态到偏向锁、轻量级锁,直至重量级锁的不同阶段及其背后的原理。

Synchronized锁的基础概念

在Java中,synchronized关键字是实现线程同步的关键机制之一,它用于确保多个线程在访问共享资源时的正确性和一致性。synchronized锁的基本思想是,当一个线程进入某个synchronized代码块或方法时,它必须首先获取到该对象或类的锁,然后才能执行相应的操作。如果其他线程试图进入相同的synchronized区域,它们将被阻塞,直到锁被释放。

对象头与Mark Word简介

Java对象在内存中不仅包含类实例的字段,还包含一些元数据,这些元数据存储在对象头中。对象头是Java对象的重要组成部分,它包含了关于对象的重要信息,如哈希码、GC年龄以及锁状态等。其中,Mark Word是对象头中的一个关键字段,它记录了关于对象锁状态的信息。通过修改Mark Word的内容,JVM能够实现对对象锁的获取和释放。

Synchronized锁定的基本原理与运作机制概述

synchronized锁定的基本原理是通过对对象或类的监视器(Monitor)进行加锁和解锁操作来实现线程同步。当一个线程尝试进入synchronized代码块或方法时,它会首先尝试获取对象或类的锁。如果锁已经被其他线程持有,则该线程将被阻塞,直到锁被释放。synchronized锁的运作机制包括偏向锁、轻量级锁和重量级锁三种状态。偏向锁适用于单线程访问的情况,轻量级锁适用于多线程竞争不激烈的情况,而重量级锁则用于处理高竞争场景。通过这三种状态的转换,synchronized锁能够根据不同的并发场景动态调整锁策略,以实现高效的线程同步。

关于synchronized的实现方式,原理介绍,请参考:美团一面:说说synchronized的实现原理?问麻了。。。。

锁升级的概念

锁升级是指Java虚拟机(JVM)在并发环境下对synchronized关键字所使用的锁机制进行动态调整的过程,从最初的无锁状态逐渐过渡到偏向锁、轻量级锁,直至最终的重量级锁。这一过程旨在根据实际的并发状况选择最适合的锁类型,以实现对共享资源的最佳保护和最有效的并发控制。

锁升级的主要目的是为了提升并发性能,减少不必要的线程上下文切换和内存消耗。线程上下文切换是一个相对昂贵的操作,因为它涉及到保存当前线程的状态、恢复另一个线程的状态等一系列操作。通过优化锁策略,JVM可以减少这种切换的频率,从而提高系统的整体性能。

另外,锁升级也有助于减少内存消耗。相较于重量级锁需要创建额外的Monitor对象并在操作系统层面进行线程调度,偏向锁和轻量级锁在一定程度上降低了内存消耗,特别是对于大量短生命周期的锁请求场景。

Synchronized锁的四种状态详解

当我们使用synchronized时,Java虚拟机(JVM)会为每个被同步的对象维护一个锁(或称为监视器锁)。这个锁有四种状态:从级别由低到高依次是:无锁、偏向锁,轻量级锁,重量级锁,用于控制多线程对共享资源的访问。

image.png

无锁

无锁状态是对象初始化后的默认锁状态,表示对象当前未被任何线程锁定。在这种状态下,对象头的锁标志位通常为空或特定的无锁标识,表明对象不受任何同步控制,任何线程都能够无障碍地访问该对象。

无锁的标志位为01,即如果是否偏向锁标识为0时是无锁状态,为1时是偏向锁。在这个状态下,没有线程拥有锁,并且存储了对象的hashcode、对象的分代年龄以及是否为偏向锁的标志(0表示不是偏向锁)。

当一个线程首次尝试获取锁时,JVM会检查这个锁是否处于无锁状态。如果是,JVM会尝试将锁偏向给这个线程,也就是将锁标记为偏向这个线程,并且将这个线程的ID记录在锁的标记中。这样,当这个线程再次尝试获取锁时,就可以避免一些昂贵的操作,因为JVM可以直接检查锁是否仍然偏向这个线程。

偏向锁

当一个线程首次成功获取一个锁时,锁就进入了偏向锁状态。在偏向锁状态下,只有持有偏向锁的线程才能再次获取这个锁,而不会引起竞争。如果其他线程尝试获取这个锁,偏向锁就会升级为轻量级锁。

偏向锁的标志位为01,即是否偏向锁表标识位为1。与无锁状态的标志位相同,但存储的内容有所不同。偏向锁状态下,会存储偏向的线程ID、偏向时间戳、对象分代年龄以及是否偏向锁的标志(1)。

偏向锁是一种针对线程独占锁优化的机制,它适用于单一线程长时间、连续地访问同一段同步代码的情况。当某个线程首次获得同步代码块的锁后,Java虚拟机会在对象头的Mark Word中记录该线程的ID,形成偏向锁。在此之后,该线程再次进入同步代码块时,无需执行CAS操作等复杂的同步动作,仅需确认Mark Word中的偏向线程ID是否为自己,便可迅速获得锁,从而极大地减少了获取锁的开销,提升了并发性能。

在偏向锁生效期间,除非有其他线程尝试获取该锁,否则持有偏向锁的线程不会主动释放锁。当出现锁竞争时,原有的偏向锁持有者会经历撤销过程。此过程发生在全局安全点,即在所有线程均停止执行字节码的时刻,JVM会暂停当前持有偏向锁的线程,检查锁对象的状态。如果发现持有偏向锁的线程不再活动或者锁确实处于被争夺状态,则会撤销偏向锁,即将对象头恢复为无锁状态(标志位为01)或直接升级为轻量级锁(标志位调整为对应轻量级锁的状态)。

偏向锁主要是为了解决在一个线程连续多次获取同一锁的情况,降低不必要的同步操作开销。当首次获取锁的线程再次进入同步代码块时,会检查对象头中存储的线程ID是否与当前线程一致。如果一致,则直接获得锁;如果不一致,则需要撤销偏向锁,重新进行锁竞争,可能升级为轻量级锁。

优点
对于没有或很少发生锁竞争的场景,偏向锁可以显著减少锁的获取和释放所带来的性能损耗。

缺点

  • 额外存储空间:偏向锁会在对象头中存储一个偏向线程ID等相关信息,这部分额外的空间开销虽然较小,但在大规模并发场景下,累积起来也可能成为可观的成本。

  • 锁升级开销:当一个偏向锁的对象被其他线程访问时,需要进行撤销(revoke)操作,将偏向锁升级为轻量级锁,甚至在更高竞争情况下升级为重量级锁。这个升级过程涉及到CAS操作以及可能的线程挂起和唤醒,会带来一定的性能开销。

  • 适用场景有限:偏向锁最适合于绝大部分时间只有一个线程访问对象的场景,这样的情况下,偏向锁的开销可以降到最低,有利于提高程序性能。但如果并发程度较高,或者线程切换频繁,偏向锁就可能不如轻量级锁或重量级锁高效。

轻量级锁

当一个线程尝试获取一个已经被其他线程持有的偏向锁时,偏向锁会升级为轻量级锁。轻量级锁是一种用于处理线程之间轻量级竞争的机制。当一个线程尝试获取轻量级锁时,它会先自旋一段时间,尝试等待锁被释放。如果在这段时间内锁被释放了,那么这个线程就可以成功获取锁。如果自旋结束后锁仍然被持有,那么这个线程就会尝试将锁升级为重量级锁。

轻量级锁的标识位为:00。当锁从偏向锁升级为轻量级锁时,标志位会变为00。在轻量级锁状态下,多个线程可能会尝试获取锁,通过自旋来等待锁被释放。

轻量级锁利用CAS操作尝试将对象头的Mark Word替换为指向线程栈中锁记录的指针,如果CAS操作成功,则表示线程成功获取锁。获取锁失败的线程会进入自旋状态,不断循环尝试获取锁,直到获取成功或升级为重量级锁。在自旋期间,线程不会立即进入阻塞状态,而是不断循环检查锁是否可用。这种机制可以减少线程上下文切换的开销,但如果自旋次数过多或者竞争加剧,自旋就会失去意义,JVM会选择升级为重量级锁。

优点

  • 低开销:轻量级锁通过CAS操作尝试获取锁,避免了重量级锁中涉及的线程挂起和恢复等高昂开销。
  • 快速响应:在无锁竞争或者锁竞争不激烈的情况下,轻量级锁使得线程可以迅速获取锁并执行同步代码块。

缺点

  • 自旋消耗:当锁竞争激烈时,线程可能会长时间自旋等待锁,这会消耗CPU资源,导致性能下降。
  • 升级开销:如果自旋等待超过一定阈值或者锁竞争加剧,轻量级锁会升级为重量级锁,这个升级过程本身也有一定的开销。

重量级锁

当轻量级锁的自旋尝试达到一定阈值,或者检测到多个线程竞争激烈时,JVM会将轻量级锁升级为重量级锁。升级过程中,会取消当前线程的自旋操作,并在对象头中设置重量级锁标志。

重量级锁的标识位为:10。当锁从轻量级锁升级为重量级锁时,标志位会变为10。在重量级锁状态下,线程在获取锁时会阻塞,直到持有锁的线程释放锁。

在重量级锁状态下,线程在获取锁失败时会被操作系统挂起,放入到该对象关联的监视器(Monitor)的等待队列中,由操作系统进行线程调度,当锁被释放时,操作系统会选择合适的线程将其唤醒并授予锁。

尽管重量级锁的开销较大,涉及到线程上下文切换和内核态用户态的切换等,但它在高竞争场景下能提供稳定的互斥性和公平性,确保数据的一致性和线程的安全执行。因此,即使性能损耗较高,也是在特定情况下必要的权衡措施。

优点

  • 强一致性:重量级锁提供了最强的线程安全性,确保在多线程环境下数据的完整性和一致性。
  • 简单易用synchronized关键字的使用简洁明了,不易出错。

缺点

  • 性能开销大:获取和释放重量级锁时需要操作系统介入,可能涉及线程的挂起和唤醒,造成上下文切换,这对于频繁锁竞争的场景来说性能代价较高。
  • 延迟较高:线程获取不到锁时会被阻塞,导致等待时间增加,进而影响系统响应速度。

以上四种锁状态优缺点对比总结如下:

类型优点缺点使用场景
偏向锁快速:无须线程上下文切换,适合单一线程多次重复获取同一线程锁的场景
低开销:只需要检查对象头标记
不适合多线程竞争的场景
竞争时需要撤销偏向锁,有一定开销
大多数时候只有一线程访问同步代码块,很少出现锁竞争的情况
轻量级锁较快:通过CAS操作和自旋避免了线程的阻塞与唤醒,减少了线程上下文切换
适用于锁竞争不激烈的场景
自旋可能导致CPU空耗,在高竞争下,大量的线程自旋会增加系统负担。
无法保证绝对的公平性
短时间的同步代码块,且锁竞争不激烈,期望快速重入和释放
重量级锁稳定可靠:严格保证互斥性和公平性
能够有效应对高度竞争的锁场景
开销大:涉及到线程上下文切换,性能较低
阻塞线程可能导致响应时间变长
高并发、高竞争的场景,需要保证数据一致性,且线程等待锁的时间较长或不可预知

关于Java中锁的分类,以及各种所得介绍,请参考:阿里二面:Java中_锁的分类_有哪些?你能说全吗?

关于Java中如何定位以及避免死锁,请参考:阿里二面:如何定位&避免_死锁_?连着两个面试问到了!

锁升级的具体步骤与流程

1.无锁到偏向锁的升级流程:

  • 当线程首次尝试获取对象锁时,JVM首先检查对象是否处于无锁状态。
  • 若处于无锁状态,JVM则立即将其标记为偏向锁,并记录下当前线程的ID。
  • 这一过程通过CAS操作实现,确保线程安全地更新对象头的Mark Word为偏向锁状态,并保存偏向线程的ID。
  • 一旦设置成功,线程便可无阻碍地进入同步代码块,后续再次获取该锁时仅需验证是否仍偏向当前线程,无需额外同步操作

而对于偏向锁的释放机制:

  • 当持有偏向锁的线程正常退出同步代码块时,JVM仅简单地更新对象头的访问计数等相关信息。
  • 由于偏向锁的设计初衷是优化同一线程对锁的反复获取,因此它并不会立即释放偏向关系,而是假设下一次仍由同一线程获取锁。

2. 偏向锁到轻量级锁的升级流程:

  • 当第二个线程尝试获取已被偏向的锁时,它会首先校验对象头是否指向当前线程的ID。
  • 若校验失败,表明锁已偏向其他线程,此时需要撤销偏向锁。
  • 撤销后,对象会回到无锁状态或过渡至轻量级锁状态。
  • 接着,新线程会尝试在其栈帧中创建锁记录,并使用CAS操作将对象头的Mark Word替换为指向该锁记录的指针。
  • 若CAS操作成功,线程即获得轻量级锁;若失败,则进入自旋状态,循环尝试获取锁。

对于轻量级锁的释放机制:

  • 持有轻量级锁的线程在退出同步代码块时,会尝试通过CAS操作将对象头恢复为原始状态,即撤销锁记录指针的替换。
  • 若CAS操作成功,则轻量级锁被顺利释放;否则,可能需要进一步的锁升级或处理。

3. 轻量级锁到重量级锁的升级流程:

  • 当轻量级锁的持有线程退出同步代码块并释放锁时,它会尝试将对象头恢复到无锁或偏向锁状态。
  • 若存在多个线程竞争锁资源,轻量级锁的释放可能导致自旋线程长时间无法获取锁。
  • JVM会综合考量自旋次数、竞争激烈程度以及系统负载等因素,决策是否将轻量级锁升级为重量级锁。
  • 一旦升级为重量级锁,原持有线程必须完成锁的释放。新来的线程将被阻塞,并被加入对象的监视器(Monitor)等待队列,由操作系统负责线程的调度管理。

对于释放重量级锁:

  • 持有重量级锁的线程在退出同步代码块时,会通过调用Monitor的释放操作来唤醒等待队列中的下一个线程。
  • 被唤醒的线程将获得锁并继续执行同步代码,确保资源的顺序访问和线程安全

image.png

锁降级与锁消除

锁降级

锁降级通常出现在使用读写锁(如Java中的ReentrantReadWriteLock)的场景中。在多线程环境下,一个线程首先获取到了写锁,那么在它持有写锁期间,任何其他线程都无法获取读锁或写锁,确保了对该资源的独占访问权以进行修改。这个在持有写锁的同时,线程会尝试获取读锁。由于该线程已经持有写锁,所以它可以成功获取读锁,而不会造成死锁或其他同步问题。然后线程释会放写锁,但仍持有读锁。此时,其他线程可以获取读锁进行读取操作,但无法获取写锁进行写入操作。

锁降级的意义在于,线程在完成写操作后,如果接下来的任务主要是读取而不是继续写入,那么通过降级能够允许其他读线程同时访问资源,提高了系统的并发性能,同时保证了数据一致性,因为所有读线程看到的都是最近一次写操作完成后的一致性视图。锁降级是针对读写锁的一种高级使用方式,用于提升多读少写的并发场景性能。

锁消除

锁消除(Lock Elimination)是一种由编译器或虚拟机在运行时进行的优化技术,其目的是去除那些不必要的锁操作。当编译器或JVM的即时编译器(JIT Compiler)在分析代码时发现某个锁保护的变量并没有发生实际的共享数据竞争,也就是说,该变量的生命周期仅限于方法内部,不会逃逸出该方法,那么这个锁就可以安全地被消除掉。

例如,如果一段同步代码块中的变量只在栈上分配并且没有其他线程可以直接访问,那么即使对该变量进行了同步也不会带来任何好处,反而增加了上下文切换和锁获取释放的开销。在这种情况下,JVM可以通过逃逸分析等手段确定该变量不存在共享状态,进而消除对它的同步操作。

锁消除则是编译器和JVM层面的一种优化技术,用于消除不必要的同步,减少锁带来的性能损耗。

总结

Synchronized锁升级机制是Java虚拟机为优化多线程环境下同步操作性能而设计的一种动态调整策略。通过偏向锁、轻量级锁和重量级锁之间的智能转换,JVM可以根据实际的并发状况在低竞争和高竞争场景下分别采取不同的锁策略,从而有效减少线程上下文切换、内存占用以及CPU空转等问题,提升系统的整体并发性能。

偏向锁适用于单一线程反复访问同一锁的情况,轻量级锁则在轻度竞争场景下通过CAS和自旋优化锁的获取和释放,而重量级锁虽然开销较大,但在高强度竞争下提供了严格的互斥性和线程调度的公平性。

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等。

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

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

相关文章

【Python】 从Python列表中获取唯一值

基本原理 在Python中,列表是一种非常灵活的数据结构,它允许存储不同类型的元素。然而,有时我们可能需要从列表中提取唯一的值,即去除重复的元素。这在处理数据集或进行数据分析时尤其有用。Python提供了几种方法来实现这一目标。…

[SCTF2019]Who is he

unity 游戏,直接输入字符串 直接修改 if 判断,看能不能直接输出flag 修改了程序逻辑,但还是输出了 明明已经把这个 if 删了 不知道为什么还会输出这串字符 应该程序还有什么引入吧,看 wp 应该先查一下程序的动态链接库 DLL 是…

渗透测试工具Cobalt strike-1.CS介绍与配置

Cobalt Strike是一款美国Red Team开发的渗透测试神器,常被业界人称为CS。最近这个工具大火,成为了渗透测试中不可缺少的利器。其拥有多种协议主机上线方式,集成了提权,凭据导出,端口转发,socket代理&#x…

亡羊补牢,一文讲清各种场景下GIT如何回退

系列文章目录 手把手教你安装Git,萌新迈向专业的必备一步 GIT命令只会抄却不理解?看完原理才能事半功倍! 常用GIT命令详解,手把手让你登堂入室 GIT实战篇,教你如何使用GIT可视化工具 GIT使用需知,哪些操作…

【ArcGISPro】CSMPlugins文件夹

在ArcGISPro软件的CSMPlugins文件夹含有以下一个应用程序的扩展 从文件的名称可以看出美国地质调查局的太空地质学与ESRI合作进行的一个软件扩展,而USGS主要是遥感影像方向的应该,所以估计该dll的主要功能是多遥感影像进行处理,支持软件的不同…

MySQL(三)查询

1、单表和多表查询 1.1 算术运算符、比较运算符及特殊运算符 1)MySQL的算术运算符 select 0.1+0.3333,0.1-0.3333,0.1*0.3333,1/2,1%2; select 1/0,100%0; select 3%2,mod(3,2); 2)MySQL的比较运算符 select 1=0,1=1,null=null; select 1<>0,1<>1,null<&…

Scala环境的搭建

要搭建Scala&#xff0c;我们必须先下载java&#xff0c;由于我的电脑已经搭建好了环境&#xff0c;因此我这里用截图来教大家搭建环境。 可以从网上搜索安装包对其进行安装 IntelliJ IDEA – 领先的 Java 和 Kotlin IDE 不建议下载最新版的&#xff0c;大家下载的版本可以下…

【大宗】第一期:大航海时代下的[集运欧线]

一、大航海时代 - 集运欧线前世今生 01 航运合约指数的诞生 ‍‍‍‍ 2023年8月18日&#xff0c;上海期货交易所的伙伴们搞了个大新闻——他们推出了一种新的期货品种&#xff0c;叫做“欧线集运”。这可不是什么普通的期货&#xff0c;它是基于一个叫做SCFIS的指数&#xf…

goimghdr,一个有趣的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个有趣的 Python 库 - goimghdr。 Github地址&#xff1a;https://github.com/corona10/goimghdr 在图像处理和分析过程中&#xff0c;识别图像文件的类型是一个常见的需求。Python自带的imghdr…

DINO结构中的exponential moving average (ema)和stop-gradient (sg)

DINO思路介绍 在 DINO 中&#xff0c;教师和学生网络分别预测一个一维的嵌入。为了训练学生模型&#xff0c;我们需要选取一个损失函数&#xff0c;不断地让学生的输出向教师的输出靠近。softmax 结合交叉熵损失函数是一种常用的做法&#xff0c;来让学生模型的输出与教师模型的…

阿赵UE引擎C++编程学习笔记——GameMode和生命周期

大家好&#xff0c;我是阿赵。   之前在介绍HelloWorld的时候&#xff0c;我们很创建了一个MyGameModeBase的c类&#xff0c;然后就可以在BeginPlay函数里面写打印的HelloWorld。这一篇主要是说一下&#xff0c;GameMode究竟是一个什么东西&#xff0c;然后UE里面的生命周期是…

huggingface 笔记:聊天模型

1 构建聊天 聊天模型继续聊天。传递一个对话历史给它们&#xff0c;可以简短到一个用户消息&#xff0c;然后模型会通过添加其响应来继续对话一般来说&#xff0c;更大的聊天模型除了需要更多内存外&#xff0c;运行速度也会更慢首先&#xff0c;构建一个聊天&#xff1a; ch…

企业文件加密实现数据泄露防护

在数字化时代&#xff0c;数据成为企业最宝贵的资产之一。然而&#xff0c;数据泄露事件频发&#xff0c;给企业带来了巨大的经济损失和声誉风险。为了保护企业的核心利益&#xff0c;实现数据泄露防护&#xff0c;企业必须采取有效的文件加密措施。 一、数据泄露的严重性 数据…

基于STM32实现智能交通灯控制系统

目录 引言环境准备智能交通灯控制系统基础代码示例&#xff1a;实现智能交通灯控制系统 GPIO控制交通灯定时器配置与使用红外传感器检测车辆用户界面与显示应用场景&#xff1a;城市交通管理与自动化控制问题解决方案与优化收尾与总结 1. 引言 本教程将详细介绍如何在STM32嵌…

汽车大灯中擎耀智能控制器在车灯智能化配置下的创新与分析

随着科技的飞速发展&#xff0c;汽车工业也在不断地进行着革新。其中&#xff0c;车灯作为汽车的重要组成部分&#xff0c;其智能化配置已经成为汽车行业的一大趋势。这种趋势不仅为消费者带来了更加安全、便捷的驾驶体验&#xff0c;同时也为商家提供了丰富的商业机会。汽车工…

JS中运算符详解

一&#xff1a;赋值运算符 1 类型 、、-、*、/等 2 如何运行 &#xff0c;是将等号右边的数赋值给左边以为例&#xff0c;let num 5&#xff1b;num2等价于numnum2 二&#xff1a;一元运算符 1 自增运算符 什么是一元运算符 只需要一个操作数就可以运算的运算符 &#x…

开源数据库同步工具DBSyncer

前言&#xff1a; 这么实用的工具&#xff0c;竟然今天才发现&#xff0c;相见恨晚呀&#xff01;&#xff01;&#xff01;&#xff01; DBSyncer&#xff08;英[dbsɪŋkɜː]&#xff0c;美[dbsɪŋkɜː 简称dbs&#xff09;是一款开源的数据同步中间件&#xff0c;提供M…

解读vue3源码-1

提示&#xff1a;看到我 请让滚去学习 vue3渲染流程 文章目录 vue3渲染流程vue3的3个核心&#xff1a;1.响应式模块(Reactivity Module)--创建响应式数据2.编译模块(Compiler Module)--模版编译器将html转换为一个渲染函数3.渲染模块(Renderer Module) 渲染流程&#xff1a;1.首…

【御控工业物联网】 Java JSON结构转换、JSON结构重构、JSON结构互换(17):数组To对象——键值互换属性重组

文章目录 一、JSON结构转换是什么&#xff1f;二、核心构件之转换映射三、案例之《JSON数组 To JSON对象》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换…

2024第三届AIGC开发者大会圆桌论坛:AI Agent中国落地发展现状及多模态结合具身智能的发展展望

在2024年第三届AIGC开发者大会上&#xff0c;多位业内专家齐聚一堂&#xff0c;共同探讨了AI Agent在中国的落地发展现状以及多模态结合具身智能的发展前景。本次圆桌论坛的嘉宾包括&#xff1a; Fast JP作者于金龙Agent创始人莫西莫必胜作者秦瑞January Agent创始人李晨 多模…