java 原子类能做什么_死磕 java原子类之终结篇(面试题)
概览
原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换。
原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分,将整个操作视作一个整体是原子性的核心特征。
在java中提供了很多原子类,笔者在此主要把这些原子类分成四大类。
原子更新基本类型或引用类型
如果是基本类型,则替换其值,如果是引用,则替换其引用地址,这些类主要有:
(1)AtomicBoolean
原子更新布尔类型,内部使用int类型的value存储1和0表示true和false,底层也是对int类型的原子操作。
(2)AtomicInteger
原子更新int类型。
(3)AtomicLong
原子更新long类型。
(4)AtomicReference
原子更新引用类型,通过泛型指定要操作的类。
(5)AtomicMarkableReference
原子更新引用类型,内部使用Pair承载引用对象及是否被更新过的标记,避免了ABA问题。
(6)AtomicStampedReference
原子更新引用类型,内部使用Pair承载引用对象及更新的邮戳,避免了ABA问题。
这几个类的操作基本类似,底层都是调用Unsafe的compareAndSwapXxx()来实现,基本用法如下:
private static void testAtomicReference() {
AtomicInteger atomicInteger = new AtomicInteger(1);
atomicInteger.incrementAndGet();
atomicInteger.getAndIncrement();
atomicInteger.compareAndSet(3, 666);
System.out.println(atomicInteger.get());
AtomicStampedReference atomicStampedReference = new AtomicStampedReference<>(1, 1);
atomicStampedReference.compareAndSet(1, 2, 1, 3);
atomicStampedReference.compareAndSet(2, 666, 3, 5);
System.out.println(atomicStampedReference.getReference());
System.out.println(atomicStampedReference.getStamp());
}
原子更新数组中的元素
原子更新数组中的元素,可以更新数组中指定索引位置的元素,这些类主要有:
(1)AtomicIntegerArray
原子更新int数组中的元素。
(2)AtomicLongArray
原子更新long数组中的元素。
(3)AtomicReferenceArray
原子更新Object数组中的元素。
这几个类的操作基本类似,更新元素时都要指定在数组中的索引位置,基本用法如下:
private static void testAtomicReferenceArray() {
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);
atomicIntegerArray.getAndIncrement(0);
atomicIntegerArray.getAndAdd(1, 666);
atomicIntegerArray.incrementAndGet(2);
atomicIntegerArray.addAndGet(3, 666);
atomicIntegerArray.compareAndSet(4, 0, 666);
System.out.println(atomicIntegerArray.get(0));
System.out.println(atomicIntegerArray.get(1));
System.out.println(atomicIntegerArray.get(2));
System.out.println(atomicIntegerArray.get(3));
System.out.println(atomicIntegerArray.get(4));
System.out.println(atomicIntegerArray.get(5));
}
原子更新对象中的字段
原子更新对象中的字段,可以更新对象中指定字段名称的字段,这些类主要有:
(1)AtomicIntegerFieldUpdater
原子更新对象中的int类型字段。
(2)AtomicLongFieldUpdater
原子更新对象中的long类型字段。
(3)AtomicReferenceFieldUpdater
原子更新对象中的引用类型字段。
这几个类的操作基本类似,都需要传入要更新的字段名称,基本用法如下:
private static void testAtomicReferenceField() {
AtomicReferenceFieldUpdater updateName = AtomicReferenceFieldUpdater.newUpdater(User.class, String.class,"name");
AtomicIntegerFieldUpdater updateAge = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
User user = new User("tong ge", 21);
updateName.compareAndSet(user, "tong ge", "read source code");
updateAge.compareAndSet(user, 21, 25);
updateAge.incrementAndGet(user);
System.out.println(user);
}
private static class User {
volatile String name;
volatile int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "name: " + name + ", age: " + age;
}
}
高性能原子类
高性能原子类,是java8中增加的原子类,它们使用分段的思想,把不同的线程hash到不同的段上去更新,最后再把这些段的值相加得到最终的值,这些类主要有:
(1)Striped64
下面四个类的父类。
(2)LongAccumulator
long类型的聚合器,需要传入一个long类型的二元操作,可以用来计算各种聚合操作,包括加乘等。
(3)LongAdder
long类型的累加器,LongAccumulator的特例,只能用来计算加法,且从0开始计算。
(4)DoubleAccumulator
double类型的聚合器,需要传入一个double类型的二元操作,可以用来计算各种聚合操作,包括加乘等。
(5)DoubleAdder
double类型的累加器,DoubleAccumulator的特例,只能用来计算加法,且从0开始计算。
这几个类的操作基本类似,其中DoubleAccumulator和DoubleAdder底层其实也是用long来实现的,基本用法如下:
private static void testNewAtomic() {
LongAdder longAdder = new LongAdder();
longAdder.increment();
longAdder.add(666);
System.out.println(longAdder.sum());
LongAccumulator longAccumulator = new LongAccumulator((left, right)->left + right * 2, 666);
longAccumulator.accumulate(1);
longAccumulator.accumulate(3);
longAccumulator.accumulate(-4);
System.out.println(longAccumulator.get());
}
问题
关于原子类的问题,笔者整理了大概有以下这些:
(1)Unsafe是什么?
(3)Unsafe为什么是不安全的?
(4)Unsafe的实例怎么获取?
(5)Unsafe的CAS操作?
(6)Unsafe的阻塞/唤醒操作?
(7)Unsafe实例化一个类?
(8)实例化类的六种方式?
(9)原子操作是什么?
(10)原子操作与数据库ACID中A的关系?
(11)AtomicInteger怎么实现原子操作的?
(12)AtomicInteger主要解决了什么问题?
(13)AtomicInteger有哪些缺点?
(14)ABA是什么?
(15)ABA的危害?
(16)ABA的解决方法?
(17)AtomicStampedReference是怎么解决ABA的?
(18)实际工作中遇到过ABA问题吗?
(19)CPU的缓存架构是怎样的?
(20)CPU的缓存行是什么?
(21)内存屏障又是什么?
(22)伪共享是什么原因导致的?
(23)怎么避免伪共享?
(24)消除伪共享在java中的应用?
(25)LongAdder的实现方式?
(26)LongAdder是怎么消除伪共享的?
(27)LongAdder与AtomicLong的性能对比?
(28)LongAdder中的cells数组是无限扩容的吗?
关于原子类的问题差不多就这么多,都能回答上来吗?点击下面的链接可以直接到相应的章节查看:
彩蛋
原子类系列源码分析到此就结束了,虽然分析的类比较少,但是牵涉的内容非常多,特别是操作系统底层的知识,比如CPU指令、CPU缓存架构、内存屏障等。
下一章,我们将进入“同步系列”,同步最常见的就是各种锁了,这里会着重分析java中的各种锁、各种同步器以及分布式锁相关的内容。
欢迎关注我的公众号“彤哥读源码”,查看更多源码系列文章, 与彤哥一起畅游源码的海洋。
java 原子类能做什么_死磕 java原子类之终结篇(面试题)相关推荐
- java任务流程_死磕 java线程系列之线程池深入解析——普通任务执行流程
(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 前面我们一起学习了Java中 ...
- java 同步锁_死磕 java同步系列之自己动手写一个锁Lock
问题 (1)自己动手写一个锁需要哪些知识? (2)自己动手写一个锁到底有多简单? (3)自己能不能写出来一个完美的锁? 简介 本篇文章的目标一是自己动手写一个锁,这个锁的功能很简单,能进行正常的加锁. ...
- java ee是什么_死磕 java集合之HashSet源码分析
问题 (1)集合(Collection)和集合(Set)有什么区别? (2)HashSet怎么保证添加元素不重复? (3)HashSet是否允许null元素? (4)HashSet是有序的吗? (5) ...
- java 手编线程池_死磕 java线程系列之自己动手写一个线程池
欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写 ...
- java方法和变量修饰符有哪些_死磕Java基础---类,变量和方法的修饰符
欢迎关注微信公众号:一个自学的程序员 类修饰符 对于类的修饰符,毫无疑问是用来修饰类的,那么,修饰类的修饰符都有哪些? 有如下这些: 1. abstract 2. final 3. private 4 ...
- hashmap修改对应key的值_死磕 java集合之HashMap源码分析
简介 HashMap采用key/value存储结构,每个key对应唯一的value,查询和修改的速度都很快,能达到O(1)的平均时间复杂度.它是非线程安全的,且不保证元素存储的顺序: 继承体系 Has ...
- java线程池深入讲解_死磕 java线程系列之线程池深入解析——生命周期
(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 上一章我们一起重温了下线程的 ...
- 2019死磕java面试题_死磕 java同步系列之开篇
简介 同步系列,这是彤哥想了好久的名字,本来是准备写锁相关的内容,但是java中的CountDownLatch.Semaphore.CyclicBarrier这些类又不属于锁,它们和锁又有很多共同点, ...
- java unsafe 详解_死磕 java魔法类之Unsafe解析
问题 (1)Unsafe是什么? (2)Unsafe具有哪些功能? (3)Unsafe为什么是不安全的? (4)怎么使用Unsafe? 简介 本章是java并发包专题的第一章,但是第一篇写的却不是ja ...
最新文章
- 用Golang写一个搜索引擎(0x05)--- 文本相关性排序
- 【董天一】IPFSFilecoin和复制证明
- 栈溢出脚本_漏洞练习之网络编程与堆栈溢出技术
- VMware vSphere 文档--总目录vSphere 5.5 6.0 6.5 6.7 7.0
- 利用容器来拆分字符串
- linux 更换 镜像源
- html+css入门(参考b站黑马
- D-link 带USB口无线路由器 配置网络共享打印机
- 区块链大戏上演!陈伟星VS朱啸虎公开互怼数个回合 | 区块链日报
- Web安全工程师成长路线
- Hanoi Tower Troubles Again! ZOJ - 1239
- weui.js slider的使用笔记
- 安装esxi6.X系统过程
- 基于java的心理健康网站的设计与实现_基于JavaEE心理健康教育网站的设计与开发.doc...
- C++病毒——感染C/C++源文件
- 上善若水——甲骨文——文字文化
- 一. button按钮防止重复点击(5秒内设置点击一次)
- msp430的DCO校准值被清除后该如何处理
- 可穿戴电子设备老化测试指南
- 计算机翻译turtle,turtle是什么意思_turtle翻译_读音_用法_翻译
热门文章
- gossip 区块链_区块链中的P2P
- java实现复制粘贴的计算器_软帝学院教你用java编写计算器(三)
- linux查看tcp络连接日志,Linux监控TCP连接数并触发日志记录
- 如何用极路由新插件【搜狐视频】进行远程下载
- 物联网协议比较 MQTT CoAP RESTful/HTTP XMPP
- emd实现信息隐藏_EMD算法原理与实现
- 备份恢复linux,备份和恢复Linux系统
- java+的数组分割符_Java:使用分隔符连接基元数组
- python使用xlrd读取xlsx文件_$ 用python处理Excel文档(1)——用xlrd模块读取xls/xlsx文档...
- 男孩读计算机好还是铁路学校好,中专学计算机好还是铁路好?