【Java EE】总结12种锁策略以及synchronized的实现原理

news2024/11/26 19:43:20

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶​
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客

系列专栏:xiaoxie的JAVAEE学习系列专栏——CSDN博客●'ᴗ'σσணღ
我的目标:"团团等我💪( ◡̀_◡́ ҂)" 

( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​+关注(互三必回)!

目录

 一.锁策略

1.悲观锁 vs 乐观锁

1.悲观锁:

2.乐观锁:

3.总结

2.重量级锁 vs 轻量级锁 

1.重量级锁:

2.轻量级锁:

3.对比:

3.自旋锁 vs  挂起等待锁

1.自旋锁:

2.挂起等待锁:

3.总结

4.可重入锁 vs 不可重入锁

1.可重入锁:

2.不可重入锁:

3.总结

5.公平锁和非公平锁

1.公平锁 (Fair Lock):

2.非公平锁 (Non-Fair Lock):

 3.总结

6.互斥锁 vs 读写锁

1.互斥锁:

2.读写锁:

3.总结:

 二.synchronized的实现原理

 1.锁升级(synchronized的自适应)

1.锁升级过程

2.偏向锁(面试常考)

1.图书馆借书证办理的例子

2.总结

2.锁消除(编译器优化策略)

3.锁粗化 


 

 一.锁策略

1.悲观锁 vs 乐观锁

1.悲观锁

  • 悲观锁认为数据在并发访问时极有可能会发生冲突,所以在数据获取阶段就先加锁,只有获得锁的线程才能进行数据的读写操作。
  • 在数据库层面,悲观锁可以通过 SELECT ... FOR UPDATEUPDATE 或 DELETE 加上 WHERE 子句锁定符合条件的数据行。
  • 在事务结束后,数据库会自动释放锁。
  • 优点:能有效避免脏读、不可重复读、幻读等问题,适合并发更新较为频繁且数据一致性要求高的场景。
  • 缺点:过度依赖锁会导致并发性能下降,尤其是在锁竞争激烈时可能出现大量线程等待,造成资源浪费和响应延迟。

2.乐观锁

  • 乐观锁假定在大多数情况下,数据在并发访问时不会有冲突,只有在提交更新时才会检查是否发生了冲突。
  • 实现方式通常是在表中增加一个版本号字段(version)或其他标识符,读取数据时不加锁,但在更新时除了原条件外还会检查版本号是否发生变化。
  • 如在JPA或Hibernate中可通过@Version注解实现乐观锁,更新时如果版本号与之前读取时不一致,则表示在此期间已有其他事务修改了数据,此时事务回滚。
  • 优点:无锁状态下读取速度快,提高了并发性能,减少了锁的竞争开销。
  • 缺点:不适合并发更新特别频繁的场景,因为随着冲突概率的增加,会有更多的事务回滚;同时,频繁的版本号检测也会带来一定的性能损耗。

3.总结

总结来说,选择悲观锁还是乐观锁取决于具体的业务场景和并发程度,悲观锁适用于冲突概率较高、对数据一致性要求严格的场景,而乐观锁适用于冲突较少、追求高并发性能的场景。 

2.重量级锁 vs 轻量级锁 

1.重量级锁

  • 实现:依赖于操作系统的Mutex Lock(互斥锁)实现,因此状态转换涉及用户态内核态的切换,开销较大。
  • 优点:适用于线程竞争激烈且锁持有时间长的场景,可以有效避免CPU资源浪费。
  • 缺点:线程阻塞和唤醒涉及系统调用,可能导致性能问题,尤其是在高并发场景下。
  • 适用场景当存在多个线程长时间竞争同一把锁时,使用重量级锁较为合适。

2.轻量级锁

  • 实现:在JDK1.6中引入,通过CAS操作尝试获取锁,避免了操作系统层面的开销。
  • 优点:在没有多线程竞争或竞争不激烈的情况下,可以提高性能,因为避免了线程的阻塞和唤醒。
  • 缺点:如果线程始终无法获得锁,长时间自旋会消耗CPU资源。
  • 适用场景:适用于线程交替执行同步块,且同步块执行速度非常快的场景。

3.对比

  • 性能:轻量级锁在没有锁竞争的情况下性能更优,而重量级锁在高竞争环境下更合适。
  • 资源消耗:轻量级锁避免了操作系统资源的消耗,而重量级锁则涉及系统调用。
  • 锁升级:JVM中的锁机制设计为一个升级过程:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁,目的是为了在不同的竞争情况下提供合适的同步机制。

3.自旋锁 vs  挂起等待锁

1.自旋锁

  • 自旋锁是一种积极的锁策略,当线程试图获取一个已被其他线程持有的锁时,不会立刻放弃处理器并进入睡眠状态,而是会不断循环(自旋)检查锁是否已被释放。
  • 这种做法的优点在于,如果锁持有者很快释放了锁,那么自旋线程能够立即获得锁,避免了线程上下文切换的开销,提升了响应速度。
  • 缺点在于,如果锁被长时间占用,自旋线程将持续占用CPU资源,导致性能浪费。因此,自旋锁适用于锁持有时间短且线程上下文切换开销较大的场景,如多核处理器环境下的短期同步

2.挂起等待锁

  • 挂起等待锁是一种消极的锁策略,当线程无法获取锁时,会选择主动让出CPU并进入等待队列(通常是被操作系统挂起),直到锁被释放并收到通知后才重新参与CPU调度
  • 这样做的优点是避免了无谓的CPU消耗,当锁被长时间占用时,自旋的线程会停止消耗CPU资源
  • 缺点是线程从等待状态恢复到运行状态需要经历上下文切换,这本身有一定的开销,尤其是频繁的上下文切换可能导致性能下降。
  • 挂起等待锁适用于锁持有时间不确定或可能较长的情况,因为它可以节省CPU资源,防止无效的循环等待

3.总结

在Java中,这两种锁策略的表现形式并不是直接作为API提供,而是JVM在实现锁机制时采取的策略,例如在自旋锁策略失效后,JVM会升级锁为重量级锁,这时线程就会进入挂起等待状态。在现代Java虚拟机中,锁机制往往是复合的,包括偏向锁、轻量级锁、重量级锁等不同层次的设计,其中轻量级锁在一定程度上借鉴了自旋锁的思想 

4.可重入锁 vs 不可重入锁

1.可重入锁

  1. 可重入锁是指同一个线程可以重复获取同一把锁,而不会发生死锁。这意味着如果一个线程已经持有了锁,当它再次请求同一把锁时,仍然可以得到许可并继续执行,而不是被阻塞。
  2. 在Java中,java.util.concurrent.locks.ReentrantLock 是一种典型的可重入锁实现,同时也支持公平锁和非公平锁的选择。
  3. 可重入锁内部会维护一个计数器,记录当前线程获取锁的次数,每获取一次锁计数器加1,每释放一次锁计数器减1,直到计数器为0时,锁真正释放。
  4. 可重入锁的优势在于支持递归调用和嵌套同步,简化了编程模型,并降低了死锁风险

2.不可重入锁

  1. 不可重入锁一旦被一个线程获取后,该线程如果再次请求该锁,就会被阻塞,无法获取,即一个线程不能再次获取自己已经持有的锁
  2. 不可重入锁不允许锁的持有线程对自己已经持有的锁进行二次锁定,因此在递归调用或者嵌套同步场景下容易产生死锁。

3.总结

总结起来,可重入锁相较于不可重入锁在处理多层同步和递归调用时具有更高的灵活性和安全性,不易引发死锁问题,但在某些特定场景下,不可重入锁也可能因其简洁性和性能特点而被选用。并且Java中的synchronized 就是可重入锁.

5.公平锁和非公平锁

1.公平锁 (Fair Lock)

  1. 公平锁是一种遵循先进先出(FIFO)原则的锁机制,当多个线程请求同一个锁时,会严格按照线程请求锁的顺序来决定哪个线程可以获得锁。也就是说,已经在等待队列中的线程会优先获得锁,不存在后来的线程抢占先来线程锁的情况。
  2. 公平锁的优势在于能够避免线程饥饿现象的发生,确保每个等待锁的线程最终都能够获得锁的机会,提高了线程调度的公平性
  3. 缺点是由于每次锁释放后都需要唤醒队列中等待最久的线程,这会增加线程上下文切换的开销,特别是在高并发场景下可能会降低系统的整体吞吐量。

2.非公平锁 (Non-Fair Lock)

  1. 非公平锁则不保证线程获取锁的顺序与请求锁的顺序一致,当锁可用时,任何等待的线程都有可能获取到锁,即使是刚刚开始等待的线程也可能优于已经在等待队列中的线程
  2. 非公平锁在没有等待队列或者锁刚释放时,允许线程“插队”,直接尝试获取锁,这种策略在某些场景下可以提高系统的整体性能,因为减少了线程上下文切换的次数。
  3. 缺点是可能导致部分线程长期得不到锁,形成线程饥饿,尤其是在连续的锁请求和释放中,总是有新来的线程抢先获得锁的情况下,这种情况尤为明显。

 3.总结

这里的公平是相对的,你也可以说,先来后到是公平的,或者是每个线程都有同等机会获取到锁是公平的,但是在Java中是这样定义公平的,在Java中,java.util.concurrent.locks.ReentrantLock类可以指定是否启用公平锁,通过构造函数传入true参数即可创建公平锁实例,否则默认为非公平锁Java的并发包中,公平锁强调的是线程获取锁的有序性和公平性,而非公平锁则倾向于提高系统的并发性能,但可能会使得部分线程在竞争锁时面临不公平待遇。开发者可以根据实际应用场景的需求来选择使用哪种类型的锁.

6.互斥锁 vs 读写锁

1.互斥锁

  1. 互斥锁是一种最基本的同步原语,它确保在同一时间只有一个线程能够访问被锁定的资源或临界区
  2. 当一个线程获取互斥锁后,其他所有试图获取相同锁的线程将被阻塞,直到拥有锁的线程释放锁为止。
  3. 在Java中,synchronized关键字以及java.util.concurrent.locks.ReentrantLock都可以实现互斥锁的功能。
  4. 互斥锁主要用于保护那些既需要进行读操作又需要进行写操作的共享资源,无论何种操作,都需要获取锁。

2.读写锁

  1. 读写锁是一种比互斥锁更细粒度的锁,它区分读操作和写操作,允许多个线程同时进行读操作,但同一时刻只允许一个线程进行写操作
  2. 当没有任何线程持有写锁时,多个读线程可以同时获取读锁并读取共享资源;一旦有线程请求写锁读线程将被阻塞,直到写锁被释放
  3. 在Java中,java.util.concurrent.locks.ReentrantReadWriteLock类是读写锁的典型实现。
  4. 读写锁适用于读操作远大于写操作的场景,可以大大提高并发读取数据的性能,减少锁竞争

3.总结

  • 互斥锁在任何时刻仅允许一个线程访问资源,无论读写
  • 读写锁允许多个线程同时读取资源,但在进行写操作时,禁止其他读写线程介入,确保数据一致性;
  • 使用读写锁可以显著提高读密集型场景下的并发性能,而互斥锁在所有情况下都能确保数据一致性,但在读多写少的情况下可能会导致性能瓶颈。

 二.synchronized的实现原理

synchronized悲观锁也是乐观锁,是重量锁,也是轻量级锁,重量级锁是自旋锁实现的,轻量级锁是挂起等待锁实现的,是可重入锁,非公平锁,以及互斥锁.

现在我们就从synchronized的实现原理来分析为什么它具有多种特性的锁机制

 1.锁升级(synchronized的自适应)

1.锁升级过程

2.偏向锁(面试常考)

synchronized中的锁升级机制中,偏向锁是一种针对无多线程竞争情况的优化。为了便于理解,我们可以用生活中的图书馆借书证办理过程来类比偏向锁的工作方式:

1.图书馆借书证办理的例子
  1. 新书证发放(偏向锁初始化): 假设你去图书馆办理借书证。在非繁忙时段,图书馆只有一个人在办理,工作人员会直接为你制作一张借书证,并将你的信息记录在证上,比如照片和姓名。这张借书证在之后的使用中会被认为“偏向”于你,因为你是第一个使用它的人。

  2. 借书(线程获得偏向锁): 当你再次来借书时,图书馆的系统会检查借书证,发现这张证已经被“偏向”于你,于是系统无需再次核对你的身份信息,直接允许你借书。这个过程非常快速,因为系统已经“认识”了你。

  3. 多人借书(锁竞争开始): 如果在某个时刻,另一个人也拿着这张借书证来借书,图书馆系统会意识到这张借书证不再“偏向”于单一的一个人,因此它需要采取更公平的方式来处理。此时,你的借书证会被“升级”,比如变成一张需要每次借书时都要核对信息的普通借书证。

  4. 借书证升级(偏向锁升级为轻量级锁或重量级锁): 根据图书馆的繁忙程度(即线程竞争的激烈程度),这张借书证可能只是简单地每次要求你出示身份证来确认身份(类似于轻量级锁),或者可能需要你排队等待,直到轮到你办理借书手续(类似于重量级锁)。

2.总结
  1. 初始无锁状态:当一个对象被创建时,它的锁对象(由对象头中的Mark Word表示)处于无锁状态。这意味着没有线程正在使用这个锁,也没有任何锁标记。

  2. 线程首次获取锁:当第一个线程尝试进入synchronized块时,如果之前没有线程获取过这个锁,JVM会给这个锁打上一个偏向标记,这个标记指向当前获取锁的线程。这个过程是非常快速的,因为实际上并没有进行真正的锁加锁操作,而只是在Mark Word中记录了线程的信息。

  3. 偏向锁:如果同一个线程再次尝试获取这个锁,JVM会检查Mark Word中的偏向标记。如果发现标记指向的是当前线程,那么JVM允许该线程直接获取锁,无需进行任何同步操作。这样就大大提高了线程获取锁的效率。

  4. 锁竞争出现:如果有另一个线程也尝试获取这个锁,JVM会检测到锁竞争。这时,偏向锁会被撤销,锁的状态会升级为轻量级锁轻量级锁使用CAS(Compare-And-Swap)操作来尝试获取锁,如果失败,线程会进行自旋等待

  5. 锁状态进一步升级:如果自旋等待仍然无法获取锁,或者有更多线程参与竞争,轻量级锁可能会进一步升级为重量级锁。重量级锁涉及到操作系统级别的锁机制,线程在获取锁失败后会被阻塞,直到锁被释放。

通过这个锁升级的过程,Java虚拟机在保证线程安全的同时,尽可能地优化了锁的性能,以适应不同的并发场景。偏向锁特别适合于那些在大部分时间里只有一个线程会访问的同步资源,这样可以避免不必要的锁开销,提高程序的执行效率。

注意:升级过程是单向的,该锁的升级过程是不可逆的也就是说,当锁升级成重量级锁时就不可能退化为轻量级锁了

2.锁消除(编译器优化策略)

锁消除是Java虚拟机(JVM)中的一个优化技术,它发生在即时编译(JIT)过程中。锁消除主要针对的是那些通过逃逸分析(Escape Analysis)确认为不会逃逸出方法的对象,即这些对象不会被其他线程所访问,因此可以被认为是线程安全的。

在多线程环境中,为了保证数据的一致性和线程安全,通常会使用同步代码块来避免并发问题。然而,在某些情况下,如果编译器能够证明某个共享资源的读写操作不存在数据竞争(即在并发执行时,不会有多个线程同时修改该资源),那么这些同步措施就是多余的。

锁消除的常见场景

  1. 栈上分配:如果一个对象的生命周期被限制在单个方法内部,并且不会逃逸到其他线程,那么这个对象上的操作可以认为是线程安全的,因此可以消除对它的锁保护。

  2. 单线程代码块:如果代码块被证明只会由一个线程执行,那么该代码块内的锁可以被消除。

  3. 方法内联:在某些情况下,当JVM对代码进行内联操作时,如果内联导致某些代码路径的执行变得不可能,那么这些路径上的锁可以被消除。

  4. 不变性变量:如果一个变量在初始化后其值不再发生变化,那么该变量是线程安全的,因为它不会被任何线程修改。

锁消除的过程

  1. 逃逸分析:JVM通过逃逸分析来确定对象的作用域,即对象是否会逃逸到其他线程。

  2. 确定锁的安全性:如果对象被证明不会逃逸,并且锁的保护范围仅限于这个对象,那么JVM可以认为这个锁是多余的。

  3. 编译器优化:在即时编译过程中,JVM的编译器会根据逃逸分析的结果,对代码进行优化,移除那些被认为是多余的锁。

锁消除的优点

  • 性能提升:消除不必要的锁操作可以减少同步开销,从而提高程序的执行效率。

  • 减少资源消耗:减少锁的使用可以降低操作系统资源的消耗,如减少对互斥量的申请。

锁消除是JVM优化的一部分,它依赖于逃逸分析和编译器的优化能力。在某些情况下,锁消除可以显著提升程序性能,但也要注意,过度优化可能会导致难以发现的并发问题,因此需要谨慎使用。

3.锁粗化 

 锁粗化是Java虚拟机(JVM)为了减少不必要的锁获取和释放操作而进行的一种优化手段。在某些情况下,连续的多个对同一对象锁的加锁和解锁操作可能会导致性能损失,因为每次加解锁都会涉及到线程状态的切换、内存屏障的插入等开销。为了提高性能,JVM会对这些连续的琐碎加锁操作进行合并,使之成为一个范围更大的锁。

1for (int i = 0; i < array.length; i++) {
2    synchronized (this) {
3        // 对数组元素进行操作
4    }
5}

在这种情况下,如果JVM检测到循环体内部的同步代码块频繁执行且涉及的对象锁是同一个,那么它可能会将锁粗化为:

1synchronized (this) {
2    for (int i = 0; i < array.length; i++) {
3        // 对数组元素进行操作
4    }
5}

通过锁粗化,可以减少系统因频繁申请和释放锁带来的性能消耗,同时也降低了死锁的可能性。但是,锁粗化的优化行为并不是总能被触发,需要满足一定的条件,例如编译器或JVM能够识别到一系列相邻的锁操作,并且这些操作都在一个很短的时间窗口内完成。

感谢你的阅读,祝你一天愉快

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

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

相关文章

网易云热评加密函数逆向(Jsrpc)

今天给大家来个jsrpc实战教程,让大家继续加深对jsrpc的理解和认识。 1、因为网易云音乐热评的加密并不在cookie上,而是参数加密,所以这里就不需要进行hook住cookie了。 2、之前就知道网易云音乐热评的加密存在之地是在下图的位置,是那个函数window.asrsea(JSON.stringify(…

我成为亚马逊云科技“技领云博主“啦

小李哥前一阵子被选为了大中华区亚马逊云科技”技领云领袖“博主项目首批成员。目前该项目也在公开招募&#xff0c;今天就给大家给大家探秘下该项目&#xff5e;1️⃣什么是”技领☁️领袖“博主项目&#xff1f; 该项目是由亚马逊云科技AWS官方发起的项目&#xff0c;主要是招…

开源代码分享(23)-基于混合整数二阶锥规划(MISOCP)的主动配电网最优潮流计算

参考文献&#xff1a; [1]乔珊. 主动配电网多源协同运行优化研究[D]. 山东大学, 2021. [2]高红均,刘俊勇,沈晓东,等. 主动配电网最优潮流研究及其应用实例 [J]. 中国电机工程学报, 2017, 37 (06): 1634-1645. DOI:10.13334/j.0258-8013.pcsee.152839. 1.引言 主动配电网技术的…

智慧养猪场视频AI智能监控与可视化管理方案

在科技日新月异的今天&#xff0c;智能化、自动化已成为众多行业追求的方向。养猪业作为传统农业的重要组成部分&#xff0c;同样迎来了技术革新的春风。特别是随着人们对食品安全等问题的日益关注&#xff0c;养猪场视频监控监管方案的智能化升级显得尤为重要。 养猪场视频智…

Java基础(运算符)

运算符 运算符和表达式 运算符&#xff1a;对字面量或者变量进行操作的符号 表达式&#xff1a;用运算符把字面量或者变量连接起来&#xff0c;符合java语法的式子就可以称为表达式&#xff1b;不同运算符连接的表达式体现的是不同类型的表达式。 算术运算符&#xff08;加…

短视频素材哪个软件好?短视频素材那里来?

在当今数字化时代&#xff0c;高质量的视频素材对于提升任何视频项目的吸引力和专业度都至关重要。以下是全球范围内精选的视频素材网站&#xff0c;每个都能为你的视频创作提供独特的视觉支持和灵感。 1. 蛙学府&#xff08;中国&#xff09; 主要提供丰富的中文视频素材&…

Centos 5 的yum源

背景 有使用较老的Centos 5 系统内部安装软件无法正常报错&#xff0c;是由于系统叫老yum源存在问题 处理方法 更换下述yum源&#xff0c;可以将其他repo源文件备份移动到其他目录&#xff0c;添加下述源后重新测试 [C5.11-base] nameCentOS-5.11 baseurlhttp://vault.c…

哈希表练习题

前言 本次博客将要写一写&#xff0c;哈希表的一些使用 哈希表主要是一个映射&#xff0c;比如数组就是一个哈希表 是一个整型对应另一个整型&#xff0c;介绍的哈希表还是要以写题目为例 第一题 242. 有效的字母异位词 - 力扣&#xff08;LeetCode&#xff09; 直接来看…

vue-manage-system 更新,后台管理系统开发更简单

vue-manage-system 近期进行了一次版本升级&#xff0c;主要是支持了更多功能、升级依赖版本和优化样式&#xff0c;并且上线了官方文档网站&#xff0c;大部分功能都有文档或者使用示例&#xff0c;更加适合新手上手开发&#xff0c;只需要根据实际业务简单修改&#xff0c;就…

【讯为Linux驱动笔记1】申请一个字符设备

Linux下每个设备都需要有一个专属设备号&#xff1a;主设备号 次设备号 【申请字符设备】 主设备号&#xff1a;一类驱动&#xff1a;如&#xff1a;USB驱动 次设备号&#xff1a;这类驱动下的某个设备 如&#xff1a;键盘鼠标 设备号是32位的dev_t类型的&#xff0c;高12位主…

STL_deque_stack_queue

Deque deque容器(双端队列) ​deque是一种双向开口的分段连续线性空间&#xff08;对外号称连续&#xff0c;使用者无法感知它是分段的&#xff09;。deque支持从头尾两端进行元素的插入和删除。deque没有容量的概念&#xff0c;因为它是动态地以分段连续空间组合而成的。随时…

同态加密原理解析

目录 1.数学介绍2.使用多项式环进行加密2.1 私钥和公钥的产生2.2 加密2.3 解密 3.同态计算3.1 同态加法3.2 同态乘法 1.数学介绍 同态加密方案基于一个难以计算的问题Ring Learning with Errorsred。这些方案中的数据在加密和未加密时都用多项式表示。 这里举一个简单的多项式…

最详细的 Windows 下 PyTorch 入门深度学习环境安装与配置 GPU 版 土堆教程

最详细的 Windows 下 PyTorch 入门深度学习环境安装与配置 CPU GPU 版 | 土堆教程 Windows 下 PyTorch 入门深度学习环境安装与配置 GPU 版 教程大纲如何使用此教程快速开始版本 Windows下判断有无NVIDIA GPU安装Anaconda作用流程下载安装 Anaconda 创建虚拟环境利用conda或者…

jmeter安装和简单使用

jmeter安装和简单使用 1. 安装 jmeter是基于Java开发的测试应用&#xff0c;其运行依赖于java环境&#xff0c;所以在下载运行jmeter前&#xff0c;先确保本机已经安装jdk或者jre&#xff0c;安装jdk步骤此处不描述。 下载jmeter&#xff1a; jmeter是Apache旗下的产品&…

电阻理论基础

电流的形成是电荷运动&#xff0c;电子方向相反&#xff0c;标量 电压&#xff1a;电势有参考点&#xff0c;是一个相对量 电阻的值不取决于电压和电流的&#xff0c; Ra表示标准电阻 R表示任意温度的电阻

数据结构:时间复杂度和空间复杂度

目录 1. 如何衡量一个算法的好坏2. 算法效率3. 时间复杂度3.1 时间复杂度的概念3.2 大O的渐进表示法3.3 推导大O阶方法3.4 常见时间复杂度计算举例 3.空间复杂度 1. 如何衡量一个算法的好坏 下面求斐波那契数列的算法好还是不好&#xff0c;为什么&#xff1f;该如何衡量一个算…

新书推荐机器学习大数据平台的构建、任务实现与数据治理

在大数据与机器学习日新月异的今天&#xff0c;构建稳定、安全、可扩展的数据平台已成为企业和研究机构的迫切需求。这本书应运而生&#xff0c;提供了详尽且实用的指南&#xff0c;帮助读者在云计算环境中构建、优化和治理大数据平台。 作者以清晰明了的写作风格&#xff0c;…

实现基于UDS LIN诊断协议的本地OTA升级

一、目标 在上篇文章LIN诊断实现MCU本地OTA升级_lin ota-CSDN博客中已经基于LIN诊断协议实现了通过PC端上位机对MCU进行本地的OTA升级&#xff0c;但是没有完全按照UDS协议实现。本篇将在上篇文章的基础上进行改进&#xff0c;实现基于UDS LIN诊断协议的本地OTA升级。本篇文章对…

C语言 | Leetcode C语言题解之第52题N皇后II

题目&#xff1a; 题解&#xff1a; struct hashTable {int key;UT_hash_handle hh; };struct hashTable* find(struct hashTable** hashtable, int ikey) {struct hashTable* tmp NULL;HASH_FIND_INT(*hashtable, &ikey, tmp);return tmp; }void insert(struct hashTabl…

nvm 使用教程

在任意目录中的空白处 按住Shift键不放&#xff0c;鼠标点击右键&#xff0c;在弹出的菜单中选择 “在此处打开 Powershell 窗口(S)”。 查看远程线上的nodejs版本 nvm ls available 查看自己安装的nodejs版本 nvm ls 切换nodejs版本号 nvm use 版本号 安装 xxx版本的nodej…