概述
文章目录
- 一、原子类基础
- 1. 什么是java原子类?
- 2. demo测试,不使用原子类测试
- 2.1 i++是否原子操作?并解释为什么?
- 3. 原子类使用场景
- 3.1 原子类如何使用
- 二、加法器(Adder)和累加器(Accumulator)
- 1. java8中为什么要新增LongAdder?
- 2. LongAdder
- 2.1 LongAdder原理
- 3. Accumulator
- 三、参考
一、原子类基础
1. 什么是java原子类?
Java中的原子类-并发编程
参考URL: https://blog.csdn.net/balsamspear/article/details/86575173
原子类包装了一个变量,然后提供对这个变量的原子操作的方法。
注意:原子类中对变量的操作,都是原子操作。
JDK在1.5时提供了很多原子类,在java.util.concurrent.atomic包下。
2. demo测试,不使用原子类测试
/**
* 这个例子很简单,起20个线程,每个线程执行1万次i++操作,预期结果应该是20万,实际结果却是7万多。
* 原因是,虽然volatile保证了有序性和可见性,但是不能保证原子性,i++不是原子操作。
*/
public class AtomicTest {
private static volatile int i;
private static void increase() {
i++;
}
public static void main(String[] args) throws Exception {
Thread[] threads = new Thread[20];
for (int k = 0; k < 20; k++) {
threads[k] = new Thread(() -> {
for (int j = 0; j < 10000; j++) {
increase();
}
});
threads[k].start();
}
for (Thread thread : threads) {
while (thread.isAlive()) {
Thread.sleep(100);
}
}
System.out.println(i);
}
}
- 这个例子很简单,起20个线程,每个线程执行1万次i++操作,预期结果应该是20万,实际结果却是7万多。
- 原因是,虽然volatile保证了有序性和可见性,但是不能保证原子性,i++不是原子操作。
2.1 i++是否原子操作?并解释为什么?
volatile为什么不能保证原子性
参考URL: https://blog.csdn.net/xdzhouxin/article/details/81236356
对于i++这样的操作,其实是分3步执行的,读取i的值,增加i的值,回写i的新值。这3步每一步都是原子操作,但是组合在一起就不一定是原子操作了。
3. 原子类使用场景
对于是需要简单的递增或者递减的需求场景,使用synchronized关键字和lock固然可以实现,但代码写的会略显冗余,且性能会有影响,此时用原子类更加方便。
3.1 原子类如何使用
上面介绍了原子类有4大类,这里以原子更新基本类型中的AtomicInteger类为例,介绍通用的API接口和使用方法。
首先是几个常用的API:
// 以原子方式将给定值与当前值相加,可用于线程中的计数使用,(返回更新的值)。
int addAndGet(int delta)
// 以原子方式将给定值与当前值相加,可用于线程中的计数使用,(返回以前的值)
int getAndAdd(int delta)
// 以原子方式将当前值加 1(返回更新的值)
int incrementAndGet()
// 以原子方式将当前值加 1(返回以前的值)
int getAndIncrement()
// 以原子方式设置为给定值(返回旧值)
int getAndSet(int newValue)
// 以原子方式将当前值减 1(返回更新的值)
int decrementAndGet() :
// 以原子方式将当前值减 1(返回以前的值)
int getAndDecrement()
// 获取当前值
get()
二、加法器(Adder)和累加器(Accumulator)
加法器(Adder)和累加器(Accumulator):原子类型的扩充与优化,主要有:LongAdder、LongAccumulator、DoubleAdder和DoubleAccumulator,比AtomicLong和AtomicDouble性能更优。
1. java8中为什么要新增LongAdder?
大家对AtomicInteger的基本实现机制应该比较了解,它们是在一个死循环内,不断尝试修改目标值,知道修改成功,如果竞争不激烈,那么修改成功的概率就很高,否则,修改失败的概率就很高,在大量修改失败时,这些原子操作就会进行多次循环尝试,因此性能就会受到影响。
在 JDK 8 中又新增了 LongAdder 这个类,这是一个针对 Long 类型的操作工具类。那么既然已经有了 AtomicLong,为何又要新增 LongAdder 这么一个类呢?
LongAdder是java8中新增的原子类,在多线程环境中,它比AtomicLong性能要高出不少,特别是写多的场景。
经过试验,LongAdder 的吞吐量大约是 AtomicLong 的十倍,不过凡事总要付出代价,LongAdder 在保证高效的同时,也需要消耗更多的空间。
2. LongAdder
在 JDK 8 中又新增了 LongAdder 这个类,这是一个针对 Long 类型的操作工具类。
2.1 LongAdder原理
死磕 java并发包之LongAdder源码分析
参考URL: https://zhuanlan.zhihu.com/p/65520633
LongAdder的原理是,在最初无竞争时,只更新base的值,当有多线程竞争时通过分段的思想,让不同的线程更新不同的段,最后把这些段相加就得到了完整的LongAdder存储的值。
3. Accumulator
Accumulator 和 Adder 非常相似,实际上 Accumulator 就是一个更通用版本的 Adder,比如 LongAccumulator 是 LongAdder 的功能增强版,因为 LongAdder 的 API 只有对数值的加减,而 LongAccumulator 提供了自定义的函数操作。
三、参考
java fork-join框架应用和分析
参考URL: https://www.iteye.com/blog/shmilyaw-hotmail-com-1897636
Fork/Join框架(一)引言
参考URL: https://ifeve.com/fork-join-1/
Fork/Join框架基本使用
参考URL: https://blog.csdn.net/tyrroo/article/details/81390202
ForkJoin框架使用和原理剖析
参考URL: https://blog.csdn.net/codingtu/article/details/88729498
最后
以上就是光亮大叔为你收集整理的JAVA并发-原子类/加法器(Adder)和累加器(Accumulator)的全部内容,希望文章能够帮你解决JAVA并发-原子类/加法器(Adder)和累加器(Accumulator)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复