网站首页 > java教程 正文
前面我用大量的篇幅分析了JDK中关于原子操作的解决方案,在不挂起线程的情况下,能够实现单一原子的操作,利用关键字volatile+CAS操作实现了Java的乐观锁。atomic包中的类的思维导向图如下:
上面把atomic包中的类分为了5大类,分别如下:
第一类:关于单一变量的原子操作,我说的单一变量是从广义上讲的,例如一个变量或者一个对象,主要包含如下类:AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference 第二类:关于数组中元素的原子操作,这里的原子操作仅仅对数组中的元素,与数组本身没有关系,主要包含如下类:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 第三类:关于对象中字段的,这一类有很多的限制,一般不太常用,主要包含如下类:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater 第四类:关于解决ABA问题的,主要包含如下类:AtomicMarkableReference、AtomicStampedReference。 第五类:关于高效的计数器的,CAS另一个缺点就是如果失败则自旋,会一直占用这CPU,所以这一类就是解决这个问题,主要包含如下类:LongAdder、LongAccumulator、DoubleAdder、DoubleAccumulator
这就是atomic包的全部类,他们都是Doug Lea大师设计的,如果真正理解,对接下来的lock包中的理解是有一定的帮助的,接下来我对每一类进行一个总结:
第一类:对基本变量和基本对象进行原子操作
对于单一基本变量boolean、int、long的原子操作都有对应的类,如果一个共享变量是这些基本变量,那么在多线程下对他们操作就有可能得不到正确的结果,这是由于Java内存模型所决定的,每一个线程都无法直接操作主内存中的数据,只能把主内存中的数据复制一份到自己的工作内存,然后对工作内存进行操作,至于什么时候刷新到主内存中,这个不确定,可能立即就刷新到主内存中,可能在某个适当的时候,所以导致每个线程都不可见,而AtomicBoolean、AtomicInteger、AtomicLong就是解决这些问题的,它通过关键字volatile来保证线程的可见性和有序性,通过CAS来保证线程的原子性,进而保证线程安全。而对于这种基本变量,CAS是通过比较值是否相等。
1:AtomicBoolean:原子更新boolean类型的值,底层是直接调用AtomicInteger来实现的 2:AtomicInteger:原子更新int类型的值,CAS是调用Unsafe中compareAndSwapInt()方法对int类型原子操作 3:AtomicLong:原子更新long类型的值,CAS是通过调用Unsafe中compareAndSwapLong()方法对long类型原子操作的。
对于单一的对象和基本变量的原理相同,不同的是AtomicReference通过比较对象的内存地址是否相同,与对象中的成员变量是否修改没有关系。
4:AtomicReference:原子更新引用类型,CAS是通过调用Unsafe中compareAndSwapObject()方法对对象原子操作的。
第二类:对数组中的元素进行原子操作
刚接触这一类的初学者来说,由于对其中的原理不太理解,他们总以为是对数组进行的原子操作,其实这是不对的,从源码中我们也可以看出底层的数组被final修饰,它是不可以变的,所有的方法都是对数组元素进行的操作,所以所有的原子操作针对的是数组中的元素,而非数组的本身。
5:AtomicIntegerArray:原子更新int类型数组中的元素,而非数组本身 6:AtomicLongArray:原子更新long类型数组中的元素,而非数组本身 7:AtomicReferenceArray:原子更新引用类型数组中的元素,而非数组本身。
第三篇文章:你真的了解AtomicIntegerArray吗?
第三类:对对象中被volatile修饰的成员变量进行原子操作
我在讲解这一类的时候也说了,这一类有很多限制,在实际的使用中好像用的不多,主要有三类,一个是对对象中int类型的成员变量原子操作,一个是对对象中long类型的成员变量原子操作,一个是对对象中引用类型的成员变量原子操作。
8:AtomicIntegerFieldUpdater:原子更新对象中int类型的成员变量 9:AtomicLongFieldUpdater:原子更新对象中long类型的成员变量 10:AtomicReferenceFieldUpdater:原子更新对象中的引用类型的成员变量
第四篇文章:AtomicIntegerFieldUpdater没有你想象的那么难
第四类:CAS中ABA解决方案
ABA问题是CAS中常见的问题,在一些场景中虽然有这个问题,但是对最终的结果并没有什么影响,但是在一些特殊的场景中就会出现问题,例如在转账的情况下,如果张三账户中有A元,张三的妻子取了N元后,账户中目前有B元,张三的父亲有存了N元后,账户中目前有A元,然后张三在存钱或者取钱时并不知道这种变化。可能这里例子不太合适,但是能够为我们理解ABA问题提供帮助,JDK为了解决ABA的问题,给我们提供了两个类
11:AtomicMarkableReference:通过一个boolean类型的标记来记录发生的变化。 12:AtomicStampedReference:通过一个int类型的标记记录繁盛的变化,它就像一个戳,每一次变化都有一个标记。
第五类:解决CAS失败后重试占用CPU高的解决方案
在低并发是如果需要记录一个计数器,我们完全可以利用AtomicLong,但是它有一个缺点,如果CAS更新失败,那它就不停的重试,直到成功才停止,在并发量不太高的情况下性能还可以,但是如果在高并发下,CAS的失败重试次数就会直线上升,导致CPU使用也直线上升,所以为了解决CAS机制这一个问题。但是利用这个计算的并不是太准确,它只是一个大概值。它的大概原理:在没有并发时或者在初始化Cell数组时,通过更新被volatile修饰的base变量记录,如果存在并发则操作Cell数组,而Cell数组是通过锁分离技术实现的。
12:LongAdder:主要在原来基础上加上或者减去一个数 13:LongAccumulate:主要在原来基础上和我们自定义的功能接口函数进行操作 14:DoubleAdder:主要对double类型加上或者减去一个double类型的数 15:DoubleAccumulate:主要对double类型和我们自定义的功能接口函数进行操作
猜你喜欢
- 2024-10-20 使用idea将Java项目打成Jar包,之后生成exe可执行文件
- 2024-10-20 一款易于使用的Java验证码软件包(javaee验证码)
- 2024-10-20 Java 覆盖 jar 包内的方法(java覆盖第三方jar中类文件)
- 2024-10-20 都说Java程序占内存多,那么Java对象究竟占多少内存?
- 2024-10-20 JAVA学习笔记之导包(java中的导包命令是哪个)
- 2024-10-20 简单介绍Java 的JAR包、EAR包、WAR包区别
- 2024-10-20 Java juc包学习笔记(java的juc包)
- 2024-10-20 Java带包结构调用命令行运行编译(java怎么使用包)
- 2024-10-20 Java并发包-atomic包-让您彻底掌握AtomicInteger源码
- 2024-10-20 package包和import导入的用法(package import作用)
你 发表评论:
欢迎- 07-21如何将 iPhone 中的联系人导出到 Excel/CSV?
- 07-21sql查询的字段数据中有逗号。放到csv文件会分开,如何解决?
- 07-21在 WebAPI 里生成 csv zip 文件(webapi怎么发布在iis上)
- 07-21如何把csv格式转换成Excel格式(csv格式怎么转换)
- 07-21如何将高程导出为XYZ或CSV高程点(如何将高程数据导入cad)
- 07-21使用python把csv汇总成excel(python怎么将csv文件中的列存入列表)
- 07-21解决PHP导出CSV文件中文乱码问题(php导出excel文件)
- 07-21使用vba将Excel 文件转成 CSV 文件
- 最近发表
-
- 如何将 iPhone 中的联系人导出到 Excel/CSV?
- sql查询的字段数据中有逗号。放到csv文件会分开,如何解决?
- 在 WebAPI 里生成 csv zip 文件(webapi怎么发布在iis上)
- 如何把csv格式转换成Excel格式(csv格式怎么转换)
- 如何将高程导出为XYZ或CSV高程点(如何将高程数据导入cad)
- 使用python把csv汇总成excel(python怎么将csv文件中的列存入列表)
- 解决PHP导出CSV文件中文乱码问题(php导出excel文件)
- 使用vba将Excel 文件转成 CSV 文件
- python爬虫25 | 爬取的数据怎么保存?CSV了解一下
- MySQL 导出数据(mysql 导出数据 判断成功)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)