李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
33.AtomicInteger原子整数
Leefs
2022-11-05 PM
1347℃
0条
[TOC] ### 前言 AtomicInteger 类底层存储一个int值,并提供方法对该int值进行原子操作。AtomicInteger 作为`java.util.concurrent.atomic`包的一部分,从Java 1.5开始引入。 接下来我们先从三个问题入手,对AtomicInteger概念有一个基本的了解。 ### 一、概述 **(1)什么是原子操作呢?** 所谓原子操作,就是一个独立且不可分割的操作。AtomicInteger 工具类提供了对整数操作的原子封装。 **(2)为什么要对整数操作进行原子封装呢?** 在 java 中,当我们在多线程情况下,对一个整型变量做加减操作时,如果不加任何的多线程并发控制,大概率会出现线程安全问题,也就是说当多线程同时操作一个整型变量的增减时,会出现运算结果错误的问题。AtomicInteger 工具类就是为了**简化整型变量的同步处理**而诞生的。 **(3)什么场景下需要使用AtomicInteger?** + 多线程并发场景下操作一个计数器,需要保证计数器操作的原子性。 + 进行数值比较,如果给定值与当前值相等,进行数值的更新操作,并实现操作的非阻塞算法。 ### 二、AtomicInteger基础用法 通过`AtomicInteger`构造方法,可以创建一个`AtomicInteger`对象,该对象的初始值默认为0。`AtomicInteger`提供get和set方法,获取底层int整数值,与设置int整数值。 ```java import java.util.concurrent.atomic.AtomicInteger; /** * Created by lilinchao * Date 2022/11/5 * Description AtomicInteger基本用法 */ public class Test01 { public static void main(String[] args) { //首先创建一个AtomicInteger对象 AtomicInteger atomicInteger = new AtomicInteger(); //在操作之前先赋值,如果不显示赋值则默认为0,就像 int 型变量使用前做初始化赋值一样。 atomicInteger.set(100); // 之后可以调用各种方法进行增减操作 // 获取当前值 System.out.println(atomicInteger.get()); // 先获取当前值,之后再对原值加100,返回之前的旧值 System.out.println(atomicInteger.getAndAdd(100)); // 先获取当前值,之后再对原值减1,返回旧值 System.out.println(atomicInteger.getAndDecrement()); } } ``` **运行结果** ``` 100 100 200 ``` ### 三、原子计数器场景 把`AtomicInteger`作为一个计数器使用,`AtomicInteger`提供了若干方法进行加法、减法的原子操作。 > 比如从一个map里面获取值,用get()方法,这是第一个操作; > > 获取到值之后给这个值加上n,这是第二个操作; > > 将进行过加法运算的值,再次放入map里面是第三个操作。 所谓操作的原子性是指:在多线程并发的场景下,上面的三个操作是原子性的,也就是不可分割的。 不会出现A线程get了数值,B线程同时也get到了该数值,两个线程同时为该值做运算并先后再次放入的情况,这种情况对于`AtomicInteger`而言是不会出现的,`AtomicInteger`操作是线程安全的、不可分割的。 **AtomicInteger相关方法** | 方法 | 说明 | | ----------------- | ------------------------------------------------------------ | | addAndGet() | 将给定的值加到当前值上,并在加法后返回新值,并保证操作的原子性。 | | getAndAdd() | 将给定的值加到当前值上,并返回旧值,并保证操作的原子性。 | | incrementAndGet() | 将当前值增加1,并在增加后返回新值。它相当于`++i`操作,并保证操作的原子性。 | | getAndIncrement() | 将当前值增加1并返回旧值。相当于`i++`操作,并保证操作的原子性。 | | decrementAndGet() | 将当前值减去1,并在减去后返回新值,相当于`--i`操作,并保证操作的原子性。 | | getAndDecrement() | 将当前值减去1,并返回旧值。它相当于 `i--`操作,并保证操作的原子性。 | **使用示例** ```java import java.util.concurrent.atomic.AtomicInteger; /** * Created by lilinchao * Date 2022/11/5 * Description AtomicInteger示例操作 */ public class Test02 { public static void main(String[] args) { AtomicInteger i = new AtomicInteger(0); // 获取并自增(i = 0, 结果 i = 1, 返回 0),类似于 i++ System.out.println(i.getAndIncrement()); // 自增并获取(i = 1, 结果 i = 2, 返回 2),类似于 ++i System.out.println(i.incrementAndGet()); // 自减并获取(i = 2, 结果 i = 1, 返回 1),类似于 --i System.out.println(i.decrementAndGet()); // 获取并自减(i = 1, 结果 i = 0, 返回 1),类似于 i-- System.out.println(i.getAndDecrement()); // 获取并加值(i = 0, 结果 i = 5, 返回 0) System.out.println(i.getAndAdd(5)); // 加值并获取(i = 5, 结果 i = 0, 返回 0) System.out.println(i.addAndGet(-5)); // 获取并更新(i = 0, p 为 i 的当前值, 结果 i = -2, 返回 0) // 其中函数中的操作能保证原子,但函数需要无副作用 System.out.println(i.getAndUpdate(p -> p - 2)); // 更新并获取(i = -2, p 为 i 的当前值, 结果 i = 0, 返回 0) // 其中函数中的操作能保证原子,但函数需要无副作用 System.out.println(i.updateAndGet(p -> p + 2)); // 获取并计算(i = 0, p 为 i 的当前值, x 为参数1, 结果 i = 10, 返回 0) // 其中函数中的操作能保证原子,但函数需要无副作用 // getAndUpdate 如果在 lambda 中引用了外部的局部变量,要保证该局部变量是 final 的 // getAndAccumulate 可以通过 参数1 来引用外部的局部变量,但因为其不在 lambda 中因此不必是 final System.out.println(i.getAndAccumulate(10, (p, x) -> p + x)); // 计算并获取(i = 10, p 为 i 的当前值, x 为参数1, 结果 i = 0, 返回 0) // 其中函数中的操作能保证原子,但函数需要无副作用 System.out.println(i.accumulateAndGet(-10, (p, x) -> p + x)); } } ``` ### 四、数值比对及交换操作 compareAndSet操作将一个内存位置的内容与一个给定的值进行比较,只有当它们相同时,才会将该内存位置的内容修改为一个给定的新值。这个过程是以单个原子操作的方式完成的。 **语法** + **compareAndSet方法**:如果`当前值==预期值`,则将值设置为给定的更新值。 ```java boolean compareAndSet(int expect, int update) ``` + `expect`是预期值 + `update`是更新值 **示例** ```java import java.util.concurrent.atomic.AtomicInteger; /** * Created by lilinchao * Date 2022/11/5 * Description compareAndSet() 方法示例 */ public class Test03 { public static void main(String[] args) { //初始值为100的atomic Integer AtomicInteger atomicInteger = new AtomicInteger(100); //当前值100 = 预期值100,所以设置atomicInteger=110 boolean isSuccess = atomicInteger.compareAndSet(100,110); System.out.println(isSuccess); //输出结果为true表示操作成功 //当前值110 = 预期值100? 不相等,所以atomicInteger仍然等于110 isSuccess = atomicInteger.compareAndSet(100,120); System.out.println(isSuccess); //输出结果为false表示操作失败 } } ``` **运行结果** ``` true false ``` ### 总结 `AtomicInteger`可以帮助我们在不使用synchronized同步锁的情况下,实现在多线程场景下int数值操作的线程安全,操作的原子性。并且使用`AtomicInteger`来实现int数值的原子操作,远比使用synchronized同步锁效率更高。 `java.util.concurrent.atomic`包不仅提供了`AtomicInteger`,还提供了AtomicBoolean布尔原子操作类、AtomicLong长整型布尔原子操作类、AtomicReference对象原子操作类、AtomicIntegerArray整型数组原子操作类、AtomicLongArray长整型数组原子操作类、AtomicReferenceArray对象数组原子操作类。 *附参考文章链接* *https://www.modb.pro/db/496148*
标签:
并发编程
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2551.html
上一篇
32.共享模型之CAS与volatile
下一篇
34.并发编程之原子引用
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
BurpSuite
Golang基础
Hive
Spark SQL
FastDFS
MyBatis
链表
MySQL
二叉树
数学
JVM
Yarn
Jenkins
Linux
线程池
Git
并发线程
前端
Shiro
SQL练习题
Kibana
容器深入研究
正则表达式
SpringCloudAlibaba
Docker
Nacos
Kafka
FileBeat
nginx
栈
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭