热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JUC学习记录(二)AtomicInteger

AtomicInteger内部调用了U

AtomicInteger

内部调用了Unsafe的方法,保证原子性;

什么是原子性:指操作要么成功要么失败(失败则进行事务回滚)

从一个例子从开始学习AtomicInteger

Executor executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executor.execute(() -> {
for (int j = 0; j < 30; j++) {
a++;
System.out.println(atomicInteger.incrementAndGet());
}
});
}

其中a的值最终小于300,而atomicInteger最终输出的值为300(顺序不定)。

a++其实可以分解成3个步骤:

  1. 从主存读取a
  2. a+1操作
  3. 将结果刷新到主存

而在多线程中,某一线程进行了a+1但是值还没刷新到主存中另一个线程又执行了读取的操作,从而导致最终的结果小于300,而atomicInteger则不存在此风险,下面分析它为什么不存在此风险。

我们看其主要的变量以及常用的API来分析它内部是如何实现的:

变量

// 获取Unsafe实例
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
// 通过Unsafe获取value的内存偏移量
private static final long VALUE;
static {
try {
VALUE = U.objectFieldOffset
// 获取类中value变量的内存偏移量
(AtomicInteger.class.getDeclaredField("value"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
// 值
private volatile int value;

常用API

从例子中的方法开始分析:

/**
* 实际调用Unsafe的方法 - CAS
*
* Atomically increments by one the current value.
*
* @return the updated value
*/

public final int incrementAndGet() {
// VALUE是当前值的偏移量
return U.getAndAddInt(this, VALUE, 1) + 1;
}
// 最终调用Unsafe中的方法
public final int getAndAddInt(Object obj, long offset, int increment) {
// value 当前值
int value;
do {
// 根据偏移量获取当前值
value = this.getIntVolatile(obj, offset);
// while循环判断当前值与预期值是否一致,一致的话将新值替换给内存中的值
} while(!this.compareAndSwapInt(obj, offset, value, value + increment));
// 返回增加前的值
return value;
}

其他常用的API与之类似,核心都是调用Unsafe中的native方法


推荐阅读
author-avatar
蒲哟独CrRz
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有