Java 乐观锁的介绍以及对compareAndSet方法的使用及理解(以AtomicBoolean为例)
2022/1/14 12:03:29
本文主要是介绍Java 乐观锁的介绍以及对compareAndSet方法的使用及理解(以AtomicBoolean为例),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1.乐观锁是什么
乐观锁可以理解为生活中乐观的人,这种人总是想着事情会往好的方向发展。与其对应的是悲观锁,同理悲观锁对应生活中悲观的人,他们总是认为事情会往坏的方向发展。两种锁没有绝对的好坏之分。他们的好坏取决于应用场景。
正如文章开头说的那样,乐观锁总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁。但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,如果没有人更新这个数据的话,就会使用原子操作去更新自己的修改,否则就不执行任何操作。这个过程可以使用两种方式实现。即版本号机制和CAS算法(compare and swap 比较与交换)。
1. 版本号机制
因为本节的重点是讲Java的乐观锁,而java的原子变量类(java.util.concurrent.atomic)是使用CAS算法实现的,所以版本号机制咱们仅作介绍,需要深入理解的可以自行查找资料哦。
版本号机制一般用于数据库,在数据库表中加一个数据版本version字段表示数据被修改的次数,当数据被修改时,version值会加一。当线程A想要更新数据值时,在读取数据的同时也会去读取version值,在提交更新时,若刚才读取的version值与当前数据库中的version值相等,则提交跟新自己的
2. CAS算法
CAS即Compare And Swap(比较与交换),是一种无锁算法,即在不使用锁的情况下实现多线程之间变量的同步,所以也叫非阻塞同步(Non- blocking Synchronization),CAS的执行过程如下图所示:
当且仅当V的值和新值N相等时,CAS通过原子操作的方式用计算结果值A来更新V的值,否则不会执行任何操作。一般情况下是自旋操作,也就是不断的重试
3. 乐观锁的缺点
(1) ABA问题
即如果一个变量V初次读取时值是A,并且在准备赋值时检查它的值仍然是A,那能说明它的值没有被其他线程修改过吗?显然不能。因为可能在准备赋值前,V的值被其他线程修改成了其他值B,然后又修改成了A,那么CAS操作就会误认为它从来没有被修改过,这个就是CAS操作的**“ABA”问题**
(2)循环时间长开销大
自旋CAS,不成功就会一直循环执行直到成功,如果长时间不成功,会给CPU带来很大的开销
(3)只能保证一个共享变量的原子操作
CAS只对单个共享变量有效,当操作涉及到多个共享变量时CAS无效。但在JDK1.5开始,提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里进行CAS操作。所以可以使用锁或者是利用AtomicReference类把多个共享变量合并成一个共享变量来操作
3.乐观锁使用场景
CAS适用于线程冲突较少的情景,一般在写操作比较少,读操作比较多的情况下推荐使用
Demo理解CompareAndSet()方法
public static void main(String[] args) { AtomicBoolean atomicBoolean = new AtomicBoolean(false); System.out.println("====================================="); System.out.println("result==>"+atomicBoolean.compareAndSet(true,false)); System.out.println("current value: " + atomicBoolean.get());//false System.out.println("====================================="); System.out.println("result1==>"+atomicBoolean.compareAndSet(true,true)); System.out.println("current1 value: " + atomicBoolean.get());//false System.out.println("====================================="); System.out.println("result2==>"+atomicBoolean.compareAndSet(false,false)); System.out.println("current2 value: " + atomicBoolean.get());//false System.out.println("====================================="); System.out.println("result3==>"+atomicBoolean.compareAndSet(false,true)); System.out.println("current3 value: " + atomicBoolean.get());//true System.out.println("====================================="); System.out.println("====================================="); System.out.println("result4==>"+atomicBoolean.compareAndSet(true,false)); System.out.println("current4 value: " + atomicBoolean.get());//false System.out.println("====================================="); }
需要注意的是compareAndSet()方法返回的是操作的结果,操作成功或者是失败,如:
方法的说明如下:
/** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * @param expect the expected value * @param update the new value * @return {@code true} if successful. False return indicates that * the actual value was not equal to the expected value. */ public final boolean compareAndSet(boolean expect, boolean update) { return U.compareAndSwapInt(this, VALUE, (expect ? 1 : 0), (update ? 1 : 0)); }
AtomicBoolean atomicBoolean = new AtomicBoolean(false); atomicBoolean.compareAndSet(true,false)
这段代码,读出的初始值是false,但是第一个参数的值代表期待的值(expect),只有当这个expect值和当前从内存中读出的值相等时,才会用新值(update)去更新当前内存中的值,返回操作成功的结果为true,否则返回false,表示操作不成功。所以上面的代码会返回false,内存中现在的值不变(因为没有更新成功),还是false
AtomicBoolean atomicBoolean = new AtomicBoolean(true); atomicBoolean.compareAndSet(true,false)
再看这段代码,从内存中读出的初始值为true,expect的值也为true,此时就可以用update的值(false)更新现在内存中的值,返回true表示操作成功。所以上面这段代码会返回true,内存中的值为false,因为更新成功了
这篇关于Java 乐观锁的介绍以及对compareAndSet方法的使用及理解(以AtomicBoolean为例)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-22项目:远程温湿度检测系统
- 2024-12-21《鸿蒙HarmonyOS应用开发从入门到精通(第2版)》简介
- 2024-12-21后台管理系统开发教程:新手入门全指南
- 2024-12-21后台开发教程:新手入门及实战指南
- 2024-12-21后台综合解决方案教程:新手入门指南
- 2024-12-21接口模块封装教程:新手必备指南
- 2024-12-21请求动作封装教程:新手必看指南
- 2024-12-21RBAC的权限教程:从入门到实践
- 2024-12-21登录鉴权实战:新手入门教程
- 2024-12-21动态权限实战入门指南