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原子类型 在进行并发编程的时候我们需要确保程序在被多个线程并发 ...
随机推荐
- 通过编写串口助手工具学习MFC过程——(二)通过“打开串口”按钮了解基本操作
通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...
- Educational Codeforces Round 72 (Rated for Div. 2) Solution
传送门 A. Creating a Character 设读入的数据分别为 $a,b,c$ 对于一种合法的分配,设分了 $x$ 给 $a$ 那么有 $a+x>b+(c-x)$,整理得到 $x&g ...
- css禁止鼠标双击选中文字
div{ -moz-user-select:none;/*火狐*/ -webkit-user-select:none;/*webkit浏览器*/ -ms-user-select:none;/*IE10 ...
- VSCode配置 Debugger for Chrome插件
Debugger for Chrome这个插件是直接在vscode里面进行调试js文件,跟谷歌的控制台是一样的功能,下载了它就不用打开浏览器的控制台就能进行打断点. 首先在左侧扩展栏找到这个插件下载好 ...
- mkfs - 创建一个 Linux 文件系统
总览 mkfs [ -V ] [ -t 文件系统类型 ] [ fs-选项 ] 文件系统 [ 块 ] 描述 mkfs mkfs 用来在指定设备创建一个 Linux 文件系统,通常是在硬盘上. 文件系统 ...
- Python小技巧:使用*解包和itertools.product()求笛卡尔积(转)
leetcode上做提示时候看到有高人用这个方法解题 [问题] 目前有一字符串s = "['a', 'b'],['c', 'd']",想把它分开成为两个列表: list1 = [' ...
- Revolver Maps-3D地球仪网站定制
这是个网站统计的小插件,大家可以看到那些国家,哪些城市对本网站进行了访问,很直观的一种表现方式. 这个小插件不需要你写任何代码,只需要去它官方网站定制你自己需要的代码.它的地址是:http://www ...
- Symbol的isConcatSpreadable方法
Symbol.isConcatSpreadable 布尔值,对象用于Array.prototype.concat()时,是否可以展开 let arr1 = ['c', 'd']; ['a', 'b'] ...
- C#基础知识之正则表达式
正则表达式 是一种匹配输入文本的模式..Net 框架提供了允许这种匹配的正则表达式引擎.模式由一个或多个字符.运算符和结构组成. 实例 下面的实例匹配了以 'S' 开头的单词: using Syste ...
- computed 与methods , watched 的区别
computed 与watched 的区别: 异步请求 数据变化 使用watched ,计算属性不支持异步 计算一个值的结果 用 computed computed 与methods的区别: comp ...