AtomicInteger 源码分析
AtomicInteger
AtomicInteger 能解决什么问题?什么时候使用 AtomicInteger?
支持原子更新的 int 值。
如何使用 AtomicInteger?
1)需要被多线程并发访问的原子计数器。
2)使用 AtomicInteger.compareAndSet 实现非阻塞的线程安全工具类。
使用 AtomicInteger 有什么风险?
1)高并发场景下,自旋 CAS 长时间失败会导致 CPU 飙升,推荐使用 LongAdder。
AtomicInteger 核心操作的实现原理?
创建实例
/**
* 可原子更新的 int 值
*/
private volatile int value;
/**
* 创建初始值为 initialValue 的新 AtomicInteger 实例
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* 创建初始值为 0 的新 AtomicInteger 实例
*/
public AtomicInteger() {
}
尝试以原子的方式更新值
/**
* 如果当前值 == 预期值,则以原子方式将当前值设置为给定的更新值
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*/
public final boolean compareAndSet(int expectedValue, int newValue) {
return U.compareAndSetInt(this, AtomicInteger.VALUE, expectedValue, newValue);
}
读取值
/**
* 读取值
* with memory effects as specified by {@link VarHandle#getVolatile}.
*/
public final int get() {
return value;
}
以原子方式将当前值加 1,并返回旧值
/**
* 以原子方式将当前值加 1,并返回旧值。
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*/
public final int getAndIncrement() {
return U.getAndAddInt(this, AtomicInteger.VALUE, 1);
}
Unsafe#
/**
* 1)原子地将给定的值累加到当前值、或指定索引为 offset 的数组元素上。
*/
@HotSpotIntrinsicCandidate
public int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
// 以 volatile 的方式读取值
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
// 返回旧值
return v;
}
@HotSpotIntrinsicCandidate
public boolean weakCompareAndSetInt(Object o, long offset,
int expected,
int x) {
return compareAndSetInt(o, offset, expected, x);
}
/**
* 如果当前值是 expected,则将目标值更新为 x,该操作具有 volatile 读和写内存语义。
* <p>This operation has memory semantics of a {@code volatile} read
* and write. Corresponds to C11 atomic_compare_exchange_strong.
*/
@HotSpotIntrinsicCandidate
public native boolean compareAndSetInt(Object o, long offset,
int expected,
int x);
以原子方式写入新值,并返回旧值
/**
* 以原子方式写入新值,并返回旧值
* with memory effects as specified by {@link VarHandle#getAndSet}.
*/
public final int getAndSet(int newValue) {
return U.getAndSetInt(this, AtomicInteger.VALUE, newValue);
}
以原子方式将当前值减 1,并返回旧值
/**
* 以原子方式将当前值减 1,并返回旧值
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*/
public final int getAndDecrement() {
return U.getAndAddInt(this, AtomicInteger.VALUE, -1);
}
以原子方式将给定值与当前值相加,并返回旧值
/**
* 以原子方式将给定值与当前值相加,并返回旧值
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*/
public final int getAndAdd(int delta) {
return U.getAndAddInt(this, AtomicInteger.VALUE, delta);
}
原子更新当前值为函数式接口 updateFunction 的计算值,并返回旧值
/**
* 原子更新当前值为函数式接口 updateFunction 的计算值,并返回旧值。
*/
public final int getAndUpdate(IntUnaryOperator updateFunction) {
// 读取旧值
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext) {
// 计算新值
next = updateFunction.applyAsInt(prev);
}
// 原子更新值,如果成功则返回旧值
if (weakCompareAndSetVolatile(prev, next)) {
return prev;
}
// 更新失败则重新读取旧值,如果出现 ABA 问题,则不会重新计算
haveNext = prev == (prev = get());
}
}
原子更新当前值为函数式接口 accumulatorFunction 的计算值,并返回旧值
/**
* 原子更新当前值为函数式接口 accumulatorFunction 的计算值,并返回旧值
*/
public final int getAndAccumulate(int x,
IntBinaryOperator accumulatorFunction) {
// 读取旧值
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext) {
// 基于旧值和 x 计算新值
next = accumulatorFunction.applyAsInt(prev, x);
}
// 原子更新旧值
if (weakCompareAndSetVolatile(prev, next)) {
return prev;
}
haveNext = prev == (prev = get());
}
}
以原子方式将当前值加 1,并返回新值
/**
* 以原子方式将当前值加 1,并返回新值
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*/
public final int incrementAndGet() {
return U.getAndAddInt(this, AtomicInteger.VALUE, 1) + 1;
}
以原子方式将当前值减 1,并返回新值
/**
* 以原子方式将当前值减 1,并返回新值
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*/
public final int decrementAndGet() {
return U.getAndAddInt(this, AtomicInteger.VALUE, -1) - 1;
}
以原子方式将给定值与当前值相加,并返回新值
/**
* 以原子方式将给定值与当前值相加,并返回新值
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*/
public final int addAndGet(int delta) {
return U.getAndAddInt(this, AtomicInteger.VALUE, delta) + delta;
}
以原子方式更新值【新值通过函数式接口计算得到,参数为旧值】,并返回新值
/**
* 以原子方式更新值【新值通过函数式接口计算得到,参数为旧值】,并返回新值。
*/
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext) {
next = updateFunction.applyAsInt(prev);
}
if (weakCompareAndSetVolatile(prev, next)) {
return next;
}
haveNext = prev == (prev = get());
}
}
以原子方式更新值【新值通过函数式接口计算得到,参数为旧值和参考更新值】,并返回新值
/**
* 以原子方式更新值【新值通过函数式接口计算得到,参数为旧值和参考更新值】,并返回新值
*/
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext) {
next = accumulatorFunction.applyAsInt(prev, x);
}
if (weakCompareAndSetVolatile(prev, next)) {
return next;
}
haveNext = prev == (prev = get());
}
}
AtomicInteger 源码分析的更多相关文章
- AtomicInteger源码分析——基于CAS的乐观锁实现
AtomicInteger源码分析——基于CAS的乐观锁实现 1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时 ...
- JDK AtomicInteger 源码分析
@(JDK)[AtomicInteger] JDK AtomicInteger 源码分析 Unsafe 实例化 Unsafe在创建实例的时候,不能仅仅通过new Unsafe()或者Unsafe.ge ...
- 并发-AtomicInteger源码分析—基于CAS的乐观锁实现
AtomicInteger源码分析—基于CAS的乐观锁实现 参考: http://www.importnew.com/22078.html https://www.cnblogs.com/mantu/ ...
- 死磕 java并发包之AtomicInteger源码分析
问题 (1)什么是原子操作? (2)原子操作和数据库的ACID有啥关系? (3)AtomicInteger是怎么实现原子操作的? (4)AtomicInteger是有什么缺点? 简介 AtomicIn ...
- AtomicInteger源码分析
问题背景 最近在看LinkedBlockingQueue看到了其中的count使用AtomicInteger修饰,之前也看过AtomicInteger的一些解释,也是似懂非懂的,今天深入的了解了其实现 ...
- AtomicInteger源码分析——基于CAS的乐观锁实
1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及 ...
- 【Java】CAS的乐观锁实现之AtomicInteger源码分析
1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及 ...
- JDK源码分析-AtomicInteger
AtomicInteger可以看做Integer类的原子操作工具类.在java.util.concurrent.atomic包下,在一些使用场合下可以取代加锁操作提高并发性.接下来就从几个方面来介绍: ...
- AtomicInteger原理&源码分析
转自https://www.cnblogs.com/rever/p/8215743.html 深入解析Java AtomicInteger原子类型 在进行并发编程的时候我们需要确保程序在被多个线程并发 ...
随机推荐
- 最长上升子序列(LIS) Medium2
JGShining's kingdom consists of 2n(n is no more than 500,000) small cities which are located in two ...
- Vue 数据持久化
方法一:使用 localStorage 存储数据 window.localStorage.setItem(key,value) 方法二:使用 vuex-persistedstate插件 vuex 存在 ...
- UITableViewCell选中后子View背景色被Clear
在TableView中,当cell 处于Hightlighted(高亮)或者Selected(选中)状态下,Cell上的子控件的背景颜色会被 Clear. 解决方法:(4种) 1. 直接设置子控件的 ...
- 切入点表达式execution()
用于描述方法 [掌握] 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常) 修饰符,一般省略 public 公共方法 * ...
- Linux 开机自动启动脚本
1)编写要执行脚本的sh文件mysetup.sh #!/bin/sh ### BEGIN INIT INFO # Provides: land.sh # Required-start: $local_ ...
- mock.js模拟ajax数据请求
在我们开发过程中存在着前端页面ui完成了,但是没有接口进行联调数据的情况,现在介绍一下用mock.js来完成数据的请求.这样在后期我们的后台接口完成后只需要更改请求的接口名字即可!前提是你的模拟字段名 ...
- C++中vecotr表示二维数组并自己实现一个Grid类
1 C++中使用vector来表示二维数组 声明一个二维数组: vector<vector<int>> dp(row, vector<int>(col)); 将变量 ...
- python set 集合操作
转自:https://www.cnblogs.com/alex3714/articles/5740985.html s = set([3,5,9,10]) #创建一个数值集合 t = set(&quo ...
- H5 FormData对象
FormData对象 2018年01月08日 14:31:53 阅读数:2635 FormData对象,可以把所有表单元素的name与value组成一个queryString,提交到后台. 在使用aj ...
- logback系列二:logback在项目中的应用
1.输出http日志 2.输出dubbo日志 3.输出interfacer日志 4.输出到access,remote,app等目录中