在介绍juc中的原子类之前,先看看官方文档对java.util.concurrent.atomic包的介绍官方文档地址这里截取翻译之后的部分描述

1. 支持对单个变量进行无锁线程安全编程
2. 类的实例`AtomicBoolean`,`AtomicInteger`,`AtomicLong`和`AtomicReference` 每个提供访问和更新相应的类型的单个变量
3. 这些类不是 java.lang.Integer和相关类的通用替代品。他们没有 定义方法,如equals,hashCode和 compareTo。由于预期原子变量会发生突变,因此对于哈希表键,它们是较差的选择。
4. `AtomicIntegerArray`,`AtomicLongArray`和`AtomicReferenceArray`类进一步扩展到这些类型的数组原子操作的支持
5. `AtomicIntegerFieldUpdater`,`AtomicLongFieldUpdater`和`AtomicReferenceFieldUpdater`是基于反射的实用程序,它们提供对关联的字段类型的访问。这些主要用于原子数据结构,其中几个volatile同一节点的字段(例如,树节点的链接)独立地接受原子更新。这些类在如何以及何时使用原子更新方面提供了更大的灵活性,但代价是基于反射的设置更加笨拙,使用不方便且保证较弱。
6. `AtomicMarkableReference`类与引用关联的单个布尔值。例如,此位可能在数据结构内使用,表示所引用的对象在逻辑上已被删除。`AtomicStampedReference`类与引用关联的整数值。例如,这可以用于表示与一系列更新相对应的版本号。

 在整个包中可以分为5种,这5中是我个人按照作用进行分类的

种类 包含的类
普通原子操作类 AtomicBoolean,AtomicInteger,AtomicLongAtomicReference
数组操作类 AtomicIntegerArray,AtomicLongArrayAtomicReferenceArray
对象中字段操作类 AtomicIntegerFieldUpdater,AtomicLongFieldUpdaterAtomicReferenceFieldUpdater
标记操作类 AtomicMarkableReferenceAtomicStampedReference
并发辅助计算类 DoubleAccumulator,DoubleAdder,LongAccumulator,LongAdder以及这些类的抽象父类Striped64

1.作用

 从上面介绍中可以看出这个类的作用是用来对单个变量进行操作的,在并发环境下可以保证线程的安全性,其中保证安全的原因是使用CAS操作对变量进行操作的,对于这种CAS操作的实现可以查看前面的一篇文章CAS以及相关的底层实现。

2.普通原子操作类

 个人划分的普通原子操作类是AtomicBoolean,AtomicInteger,AtomicLongAtomicReference各个类的作用分别是

类名 作用
AtomicBoolean 一个可以原子更新值boolean值的类
AtomicInteger 一个可以原子更新int类型变量值的类
AtomicLong 一个可以原子更新long类型变量值的类
AtomicReference 一个可以原子更新对象引用的类
2.1 AtomicInteger,AtomicLong

AtomicLong中的方法跟 AtomicInteger中提供的方法是一模一样的,这里用代码简单演示一下AtomicLong中的方法

public class AtomicTest {public static void main(String[] args) {AtomicInteger integer = new AtomicInteger();//设置值integer.set(1);//跟set一样也是设置值,只不过set方法能保证可见性,而lazySet不行integer.lazySet(2);//CAS操作,比较交换integer.compareAndSet(2,3);//自增后获取值integer.incrementAndGet();//与指定的值相加后返回integer.addAndGet(2);//获取之后进行自增integer.getAndIncrement();System.out.println(integer.get());}
}

 这里只列举了部分的方法,大部分方法的作用看方法名就能明白。关于set方法跟lazySet的区别,这里可以看前面写的一篇文章java的JUC包下AtomicXXX中的set跟lazySet区别以及lazySet的原理。

2.2 AtomicBoolean

AtomicBoolean其实是用一个int类型的值来表示truefalse的,如果是true则用1表示,如果是false则用0表示。其初始化方法就可以看出来

    public AtomicBoolean(boolean initialValue) {value = initialValue ? 1 : 0;}

 因此其底层的实现的方式跟AtomicBoolean是一样的,还是简单的列举一下部分方法

public class AtomicBooleanTest {public static void main(String[] args) {AtomicBoolean atomicBoolean = new AtomicBoolean(true);System.out.println(atomicBoolean.get());boolean setResult1 = atomicBoolean.compareAndSet(false, true);System.out.println(setResult1);boolean setResult2 = atomicBoolean.compareAndSet(true, false);System.out.println(setResult2);System.out.println(atomicBoolean.get());}
}

运行结果

true
false
true
false
2.3 AtomicReference

AtomicReference作用是更新一个对象。维护的是这个变量的地址值。在更新的时候校验这个的对象是不是初始化时候的对象的引用地址,不是则不给予更新,是的就更新。同时还可以定义更新的操作函数。这里列举部分测试代码

public class AtomicReferenceTest {@Testpublic void test() {Object referenceOne = new Object();Object referenceTwo = new Object();AtomicReference<Object> atomicReferenceOne = new AtomicReference<>(referenceOne);System.out.println(atomicReferenceOne.get());//compareAndSet时候原始的对象必须是创建AtomicReference的时候设置的对象boolean resultOne = atomicReferenceOne.compareAndSet(referenceTwo, referenceOne);System.out.println(resultOne);//compareAndSet时候原始的对象必须是创建AtomicReference的时候设置的对象boolean resultTwo = atomicReferenceOne.compareAndSet(referenceOne, referenceTwo);System.out.println(resultTwo);//获取然后更新函数执行结果返回的值atomicReferenceOne.getAndUpdate((one -> referenceTwo));System.out.println(atomicReferenceOne.get());}
}

3.数组操作类

 用来操作数组的原子类AtomicIntegerArray,AtomicLongArrayAtomicReferenceArray。分别对应操作int数组,long数组以及object类型数组。

3.1AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray

 这里用AtomicIntegerArray作为示例,因为这两个类实现是一样的,只不过接收的数据类型不一有。先看看对应的重要部分,偏移量的计算方式

 static {//获取当前数组的规模int scale = unsafe.arrayIndexScale(long[].class);//数组的大小需要是2的倍数if ((scale & (scale - 1)) != 0)throw new Error("data type scale not a power of two");//计算当前数组的长度是2的多少倍shift = 31 - Integer.numberOfLeadingZeros(scale);}private static long byteOffset(int i) {//计算当前元素的实际偏移量=数组的起始偏移量+当前元素在数组的位置return ((long) i << shift) + base;}

 知道了计算偏移量的方式,就好操作数组中的对应的元素了。所有的对数组中数据的操作,都是通过偏移量来进行的。

public class AtomicIntegerArrayTest {@Testpublic void test() {AtomicIntegerArray array = new AtomicIntegerArray(new int[]{1, 2, 3, 4,5});//获取指定index=2的数据System.out.println(array.get(2));//在指定index=2的数据上加上1后获取结果System.out.println(array.addAndGet(2,1));//获取指定index=2的数据System.out.println(array.get(2));//比较交换指定index=2的值为4,因为值是4而期望的3所以失败System.out.println(array.compareAndSet(2,3,4));;//比较交换指定index=2的值为3,因为值是4期望的4所以成功System.out.println(array.compareAndSet(2,4,3));;}
}

4.对象字段操作类

4.1AtomicIntegerFieldUpdater,AtomicLongFieldUpdaterAtomicReferenceFieldUpdater

AtomicIntegerFieldUpdater,AtomicLongFieldUpdaterAtomicReferenceFieldUpdater都是对一个指定对象中的指定字段进行操作。这里需要注意以下几点

  1. 对应的字段必须非private修饰
  2. 对应的字段必须是volatile修饰的
  3. AtomicIntegerFieldUpdater操作的字段必须是int类型,AtomicLongFieldUpdater操作的字段必须是long类型,AtomicReferenceFieldUpdater的操作字段必须是创建AtomicReferenceFieldUpdater对象时候指定字段的类型

 这里解释一下为什么要满足上面几点。

  1. 因为这些类对字段进行操作都是利用反射进行操作的。
  2. 要保证原子性以及可见性就需要用volatile修饰
  3. AtomicIntegerFieldUpdater会判断操作字段是不是int类型,同理AtomicLongFieldUpdater会判断是不是long类型

 列举一下部分方法以及使用方式

public class AtomicXXXFieldUpdaterTest {@Testpublic void test() {TestObject objectOne = new TestObject();//创建一个指定对象指定字段的操作的AtomicIntegerFieldUpdaterAtomicIntegerFieldUpdater<TestObject> integerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(TestObject.class, "age");//compareAndSet指定对象的某个int类型字段System.out.println(integerFieldUpdater.compareAndSet(objectOne,23,22));System.out.println(integerFieldUpdater.compareAndSet(objectOne,22,23));//创建一个指定对象指定字段的操作的AtomicLongFieldUpdaterAtomicLongFieldUpdater<TestObject> longFieldUpdater = AtomicLongFieldUpdater.newUpdater(TestObject.class, "years");//compareAndSet指定对象的某个long类型字段System.out.println(longFieldUpdater.compareAndSet(objectOne,2019L,2018L));System.out.println(longFieldUpdater.compareAndSet(objectOne,2018L,2019L));//创建一个指定对象指定类型字段的操作的AtomicReferenceFieldUpdaterAtomicReferenceFieldUpdater<TestObject,String> referenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(TestObject.class,String.class, "name");//compareAndSet指定对象的指定类型字段System.out.println(referenceFieldUpdater.compareAndSet(objectOne,"szh","acy"));System.out.println(referenceFieldUpdater.compareAndSet(objectOne,"acy","szh"));}
}class TestObject{protected volatile String name="acy";public volatile int age=22;protected volatile long years=2018L;public Long getYears() {return years;}public void setYears(Long years) {this.years = years;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}

5. 标记操作类

5.1 AtomicMarkableReferenceAtomicStampedReference

AtomicMarkableReferenceAtomicStampedReference都是标记一个类,然后根据类的引用以及标记来判断是否允许操作的类。其中AtomicMarkableReference只能标记为true或者falseAtomicStampedReference的标记只能是int类型的,通常作为更新的版本号,也就是用来解决ABA问题。两者的实现方式相同,都是维护一个内部类分别记录对象以及版本号。简单介绍一下用法。

public class AtomicXXXFieldUpdaterTest {@Testpublic void test() {Object objOne = new Object();Object objTwo = new Object();AtomicMarkableReference<Object> markableReference = new AtomicMarkableReference<>(objOne, true);//设置标记需要reference符合System.out.println(markableReference.attemptMark(objTwo,false));System.out.println("设置mark需要reference符合"+markableReference.attemptMark(objOne,false));//设置成功需要reference跟标记都是符合的System.out.println(markableReference.compareAndSet(objTwo,objOne,false,true));System.out.println(markableReference.compareAndSet(objTwo,objOne,true,false));System.out.println("设置成功需要reference跟mark都是符合的-----"+markableReference.compareAndSet(objOne,objTwo,false,true));AtomicStampedReference<Object> stampedReference = new AtomicStampedReference<>(objOne, 0);//设置标记需要reference符合System.out.println(stampedReference.attemptStamp(objTwo,2));System.out.println("设置stamp需要reference符合"+stampedReference.attemptStamp(objOne,1));//设置成功需要reference跟标记都是符合的System.out.println(stampedReference.compareAndSet(objTwo,objOne,0,1));System.out.println(stampedReference.compareAndSet(objTwo,objOne,1,0));System.out.println("设置成功需要reference跟stamp都是符合的------"+stampedReference.compareAndSet(objOne,objTwo,1,0));}
}

6.并发辅助计算类

6.1Striped64,DoubleAccumulator,DoubleAdder,LongAccumulator,LongAdder

Striped64是一个可以在并发环境下面计数用的一个组件。这个类的思想可以参考ConcurrentHashMapsize方法。Striped64的设计思路是在竞争激烈的时候尽量分散竞争,在实现上,Striped64维护了一个base Count和一个Cell数组,计数线程会首先试图更新base变量,如果成功则退出计数,否则会认为当前竞争是很激烈的,那么就会通过Cell数组来分散计数,Striped64根据线程来计算哈希,然后将不同的线程分散到不同的Cell数组的index上,然后这个线程的计数内容就会保存在该Cell的位置上面,基于这种设计,最后的总计数需要结合base以及散落在Cell数组中的计数内容。这里可以参考一下这篇博文并发之Striped64。
DoubleAccumulator,DoubleAdder,LongAccumulator,LongAdder都是Striped64的字类。主要是对数相加跟求和以及转化上的方法。这里就不多介绍了。

6.juc包下的原子类AtomicInteger,AtomicLong等AtomicXXX介绍相关推荐

  1. 源码学习【原子类AtomicInteger】Java原子类底层实现(解释详细)

    原子类AtomicInteger 在Java中,有很多方法可以保证多线程下数据的安全,AtomicXXXX这些类就是其中的一种,原子类,可以保证每一步操作都是原子操作.这次就对AtomicIntege ...

  2. java原子类场景,CAS你知道吗?原子类AtomicInteger的ABA问题谈谈?,原子共面问题...

    CAS你知道吗?原子类AtomicInteger的ABA问题谈谈?,原子共面问题(1)CAS是什么? 比较并交换 举例1,  CAS产生场景代码? importjava.util.concurrent ...

  3. 多线程十 JUC包下的常用工具类

    JUC包下的常用工具类 1. CountDownLatch-闭锁 2. CyclicBarrier-循环栅栏 3. Semaphore-信号量 4. Exchanger-线程数据交换器 这篇文章主要是 ...

  4. java并发:原子类之AtomicLong

    原子类之AtomicLong java线程中的操作,需要满足原子性.可见性等原则,比如i++这样的操作不具备原子性, A线程读取了i,另一个线程执行i++,A线程再执行i++就会引发线程安全问题 推荐 ...

  5. java atomiclong 使用_java并发:原子类之AtomicLong

    原子类之AtomicLong java线程中的操作,需要满足原子性.可见性等原则,比如i++这样的操作不具备原子性, A线程读取了i,另一个线程执行i++,A线程再执行i++就会引发线程安全问题 推荐 ...

  6. JUC多线程:Atomic原子类与CAS原理

    一.Atomic 原子类的原理: Atomic 原子操作类是基于无锁 CAS + volatile 实现的,并且类中的所有方法都使用 final 修饰,进一步保证线程安全.而 CAS 算法的具体实现方 ...

  7. 多线程与高并发(三):JUC包下新的同步机制:CAS,AtomicInteger,AtomicLong,ReentrantLock,CountDownLatch,ReadWriteLock等

    CAS CAS 是一种乐观锁,syncronized 是一种悲观锁 AtomicInteger AtomicInteger count = new AtomicInteger(0); /*synchr ...

  8. java原子整数_多线程(四、原子类-AtomicInteger)

    案例 10个线程并发累加一个整数,每个线程累加1000,保证线程安全 Unsafe类,来源于sun.misc包.该类封装了许多类似指针操作,可以直接进行内存管理.操纵对象.阻塞/唤醒线程等操作. pa ...

  9. 111 多线程JUC包下代码分析

    2019独角兽企业重金招聘Python工程师标准>>> Java多线程系列目录(共43篇) AtomicLongFieldUpdater:通过反射+CAS实现对传入对象的指定long ...

最新文章

  1. php数据库html文本,关于php,mysql,html的数字分页和文本_php
  2. Windows 7 扩展玻璃效果(Aero Glass)
  3. Go 导入当前项目下的包
  4. 解决Winform程序在不同分辨率系统下界面混乱问题
  5. 数据科学家数据分析师_站出来! 分析人员,数据科学家和其他所有人的领导和沟通技巧...
  6. g开头的C语言编程软件,C语言函数大全(g开头)
  7. Python最实用的25个小技巧
  8. 开源内容管理系统 php mysql_十大免费PHP+MySql平台内容管理系统推荐
  9. 收藏 | 让你纵横 GitHub 的五大神器
  10. Linux教程系列-命令大全
  11. 毫米波雷达测距/测速原理介绍_小七自学笔记
  12. 使用JavaScript使浏览器进入全屏或退出全屏
  13. ​2 万字系统总结,带你实现 Linux 命令自由!
  14. Transphorm第三代经JEDEC认证的GaN半导体将助力稳态光电全新的1.6 kW钛金级ATX PC游戏电源
  15. 陈平原:《阅读大学的六种方式》[转]
  16. 一种基于深度学习的目标检测提取视频图像关键帧的方法
  17. Android开发越来越式微了吗?,flutter二维码扫描第三方
  18. 单点登录(一)| LDAP 协议
  19. win11安装Ubuntu错误Installing, this may take a few minutes… WslRegisterDistribution failed with error: 0
  20. 支付宝产品签约-“系统综合评估签约条件不满足”解决办法

热门文章

  1. 我的世界服务器工业无限电,我的世界Minecraft工业服务器1.7.10
  2. 不可思议有氧机器人_不思议迷宫这七个彩蛋机器人你都有了嘛
  3. 【精华】excel办公常用小技巧
  4. 文件流下载ppt文件无法打开或文件已损坏
  5. matlab解决迷宫问题,用matlab处理蚂蚁迷宫问题
  6. ubuntu下 登陆电信“闪讯”的方法
  7. 基于pboc的电子钱包的圈存过程
  8. Git 安装(二) 之 配置环境变量
  9. ubuntu20.04 更换中国镜像
  10. 让Win10的Edge浏览器更流畅