原子类之AtomicInteger
前言
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整数值。
1 |
|
运行结果
1 |
|
三、原子计数器场景
把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-- 操作,并保证操作的原子性。 |
使用示例
1 |
|
四、数值比对及交换操作
compareAndSet操作将一个内存位置的内容与一个给定的值进行比较,只有当它们相同时,才会将该内存位置的内容修改为一个给定的新值。这个过程是以单个原子操作的方式完成的。
语法
- compareAndSet方法:如果
当前值==预期值
,则将值设置为给定的更新值。
1 |
|
expect
是预期值update
是更新值
示例
1 |
|
运行结果
1 |
|
总结
AtomicInteger
可以帮助我们在不使用synchronized同步锁的情况下,实现在多线程场景下int数值操作的线程安全,操作的原子性。并且使用AtomicInteger
来实现int数值的原子操作,远比使用synchronized同步锁效率更高。
java.util.concurrent.atomic
包不仅提供了AtomicInteger
,还提供了AtomicBoolean布尔原子操作类、AtomicLong长整型布尔原子操作类、AtomicReference对象原子操作类、AtomicIntegerArray整型数组原子操作类、AtomicLongArray长整型数组原子操作类、AtomicReferenceArray对象数组原子操作类。