短视频制作完成网站香格里拉网站建设
2026/1/9 8:16:23 网站建设 项目流程
短视频制作完成网站,香格里拉网站建设,企业网站建设如何去规划,织梦系统怎么做单页网站如果将悲观锁#xff08;Pessimistic Lock#xff09;和乐观锁#xff08;PessimisticLock 或 OptimisticLock#xff09;对应到现实生活中来。悲观锁有点像是一位比较悲观#xff08;也可以说是未雨绸缪#xff09;的人#xff0c;总是会假设最坏的情况#xff0c;避免…如果将悲观锁Pessimistic Lock和乐观锁PessimisticLock 或 OptimisticLock对应到现实生活中来。悲观锁有点像是一位比较悲观也可以说是未雨绸缪的人总是会假设最坏的情况避免出现问题。乐观锁有点像是一位比较乐观的人总是会假设最好的情况在要出现问题之前快速解决问题。在程序世界中乐观锁和悲观锁的最终目的都是为了保证线程安全避免在并发场景下的资源竞争问题。但是相比于乐观锁悲观锁对性能的影响更大什么是悲观锁悲观锁总是假设最坏的情况认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改)所以每次在获取资源操作的时候都会上锁这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。也就是说共享资源每次只给一个线程使用其它线程阻塞用完后再把资源转让给其它线程。像 Java 中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。public void performSynchronisedTask() { synchronized (this) { // 需要同步的操作 } } private Lock lock new ReentrantLock(); lock.lock(); try { // 需要同步的操作 } finally { lock.unlock(); }一键获取完整项目代码java高并发的场景下激烈的锁竞争会造成线程阻塞大量阻塞线程会导致系统的上下文切换增加系统的性能开销。并且悲观锁还可能会存在死锁问题影响代码的正常运行。什么是乐观锁乐观锁总是假设最好的情况认为共享资源每次被访问的时候不会出现问题线程可以不停地执行无需加锁也无需等待只是在提交修改的时候去验证对应的资源也就是数据是否被其它线程修改了具体方法可以使用版本号机制或 CAS 算法。像 Java 中java.util.concurrent.atomic包下面的原子变量类比如AtomicInteger、LongAdder就是使用了乐观锁的一种实现方式CAS实现的。// LongAdder 在高并发场景下会比 AtomicInteger 和 AtomicLong 的性能更好 // 代价就是会消耗更多的内存空间空间换时间 LongAdder longAdder new LongAdder(); // 自增 longAdder.increment(); // 获取结果 longAdder.sum();一键获取完整项目代码java高并发的场景下乐观锁相比悲观锁来说不存在锁竞争造成线程阻塞也不会有死锁的问题在性能上往往会更胜一筹。但是如果冲突频繁发生写占比非常多的情况会频繁失败和重试悲观锁的开销是固定的这样同样会非常影响性能导致 CPU 飙升。不过大量失败重试的问题也是可以解决的像我们前面提到的LongAdder以空间换时间的方式就解决了这个问题。理论上来说悲观锁通常多用于写比较多的情况下多写场景竞争激烈这样可以避免频繁失败和重试影响性能悲观锁的开销是固定的。不过如果乐观锁解决了频繁失败和重试这个问题的话比如LongAdder也是可以考虑使用乐观锁的要视实际情况而定。乐观锁通常多于写比较少的情况下多读场景竞争较少这样可以避免频繁加锁影响性能。不过乐观锁主要针对的对象是单个共享变量参考java.util.concurrent.atomic包下面的原子变量类。篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc需要全套面试笔记及答案【点击此处即可/免费获取】https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1ho如何实现乐观锁乐观锁一般会使用版本号机制或 CAS 算法实现CAS 算法相对来说更多一些这里需要格外注意。版本号机制一般是在数据表中加上一个数据版本号version字段表示数据被修改的次数。当数据被修改时version值会加一。当线程 A 要更新数据值时在读取数据的同时也会读取version值在提交更新时若刚才读取到的 version 值为当前数据库中的version值相等时才更新否则重试更新操作直到更新成功。举一个简单的例子假设数据库中帐户信息表中有一个 version 字段当前值为 1 而当前帐户余额字段balance为 $100 。操作员 A 此时将其读出version1 并从其帐户余额中扣除 $50 $100-$50 。在操作员 A 操作的过程中操作员 B 也读入此用户信息version1 并从其帐户余额中扣除 $20 $100-$20 。操作员 A 完成了修改工作将数据版本号version1 连同帐户扣除后余额balance$50 提交至数据库更新此时由于提交数据版本等于数据库记录当前版本数据被更新数据库记录version更新为 2 。操作员 B 完成了操作也将版本号version1 试图向数据库提交数据balance$80 但此时比对数据库记录版本时发现操作员 B 提交的数据版本号为 1 数据库记录当前版本也为 2 不满足 “ 提交版本必须等于当前版本才能执行更新 “ 的乐观锁策略因此操作员 B 的提交被驳回。这样就避免了操作员 B 用基于version1 的旧数据修改的结果覆盖操作员 A 的操作结果的可能。CAS 算法CAS 的全称是Compare And Swap比较与交换用于实现乐观锁被广泛应用于各大框架中。CAS 的思想很简单就是用一个预期值和要更新的变量值进行比较两值相等才会进行更新。CAS 是一个原子操作底层依赖于一条 CPU 的原子指令。原子操作即最小不可拆分的操作也就是说操作一旦开始就不能被打断直到操作完成。CAS 涉及到三个操作数V要更新的变量值(Var)E预期值(Expected)N拟写入的新值(New)当且仅当 V 的值等于 E 时CAS 通过原子方式用新值 N 来更新 V 的值。如果不等说明已经有其它线程更新了 V则当前线程放弃更新。举一个简单的例子线程 A 要修改变量 i 的值为 6i 原值为 1V 1E1N6假设不存在 ABA 问题。i 与 1 进行比较如果相等 则说明没被其他线程修改可以被设置为 6 。i 与 1 进行比较如果不相等则说明被其他线程修改当前线程放弃更新CAS 操作失败。当多个线程同时使用 CAS 操作一个变量时只有一个会胜出并成功更新其余均会失败但失败的线程并不会被挂起仅是被告知失败并且允许再次尝试当然也允许失败的线程放弃操作。Java 语言并没有直接实现 CASCAS 相关的实现是通过 C 内联汇编的形式实现的JNI 调用。因此 CAS 的具体实现和操作系统以及 CPU 都有关系。sun.misc包下的Unsafe类提供了compareAndSwapObject、compareAndSwapInt、compareAndSwapLong方法来实现的对Object、int、long类型的 CAS 操作/** * CAS * param o 包含要修改field的对象 * param offset 对象中某field的偏移量 * param expected 期望值 * param update 更新值 * return true | false */ public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object update); public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update); public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);一键获取完整项目代码java篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc需要全套面试笔记及答案【点击此处即可/免费获取】https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1ho乐观锁存在哪些问题ABA 问题是乐观锁最常见的问题。ABA 问题如果一个变量 V 初次读取的时候是 A 值并且在准备赋值的时候检查到它仍然是 A 值那我们就能说明它的值没有被其他线程修改过了吗很明显是不能的因为在这段时间它的值可能被改为其他值然后又改回 A那 CAS 操作就会误认为它从来没有被修改过。这个问题被称为 CAS 操作的ABA问题。ABA 问题的解决思路是在变量前面追加上版本号或者时间戳。JDK 1.5 以后的AtomicStampedReference类就是用来解决 ABA 问题的其中的compareAndSet()方法就是首先检查当前引用是否等于预期引用并且当前标志是否等于预期标志如果全部相等则以原子方式将该引用和该标志的值设置为给定的更新值。public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { PairV current pair; return expectedReference current.reference expectedStamp current.stamp ((newReference current.reference newStamp current.stamp) || casPair(current, Pair.of(newReference, newStamp))); }一键获取完整项目代码java循环时间长开销大CAS 经常会用到自旋操作来进行重试也就是不成功就一直循环执行直到成功。如果长时间不成功会给 CPU 带来非常大的执行开销。如果 JVM 能支持处理器提供的 pause 指令那么效率会有一定的提升pause 指令有两个作用可以延迟流水线执行指令使 CPU 不会消耗过多的执行资源延迟的时间取决于具体实现的版本在一些处理器上延迟时间是零。可以避免在退出循环的时候因内存顺序冲而引起 CPU 流水线被清空从而提高 CPU 的执行效率。只能保证一个共享变量的原子操作CAS 只对单个共享变量有效当操作涉及跨多个共享变量时 CAS 无效。但是从 JDK 1.5 开始提供了AtomicReference类来保证引用对象之间的原子性你可以把多个变量放在一个对象里来进行 CAS 操作.所以我们可以使用锁或者利用AtomicReference类把多个共享变量合并成一个共享变量来操作。总结高并发的场景下激烈的锁竞争会造成线程阻塞大量阻塞线程会导致系统的上下文切换增加系统的性能开销。并且悲观锁还可能会存在死锁问题影响代码的正常运行。乐观锁相比悲观锁来说不存在锁竞争造成线程阻塞也不会有死锁的问题在性能上往往会更胜一筹。不过如果冲突频繁发生写占比非常多的情况会频繁失败和重试这样同样会非常影响性能导致 CPU 飙升。乐观锁一般会使用版本号机制或 CAS 算法实现CAS 算法相对来说更多一些这里需要格外注意。CAS 的全称是Compare And Swap比较与交换用于实现乐观锁被广泛应用于各大框架中。CAS 的思想很简单就是用一个预期值和要更新的变量值进行比较两值相等才会进行更新。乐观锁的问题ABA 问题、循环时间长开销大、只能保证一个共享变量的原子操作。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询