AtomicInteger定义
- AtomicInteger类是系统底层保护的int类型,通过对int类型的数据进行封装,提供执行方法的控制进行值的原子操作,但AtomicInteger ≠ Integer。
- AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。
AtomicInteger使用场景
- AtomicInteger提供原子操作来进行Integer的使用,适合高并发情况下的使用。
- foreach作循环的时候需要对应参数进行自增或者自减操作。
AtomicInteger作用
分析普通Java的运算操作:
Java 中的运算操作在多线程是线程不安全的。比如 i++
会解析为 i=i+1
,Java 程序会把算式分为 3 个操作,获取值,计算值,赋予值,i++
这个操作不具备原子性,多线程并发共享变量时必然会出现问题。
原子性:指的就是一个操作是不可中断,即使有多个线程执行,一个操作开始也不会受其他线程影响,即可以理解为线程的最小执行单元,不可被分割
线程不安全:一个线程计算出值后,还未重新给变量赋值,另一个线程来读取到这个值,就会造成线程不安全的问题
加锁:有时候需要通过加锁的方式去保证线程安全,但是加锁对性能会有很大的影响。
AtomicInteger的作用:就是让程序在不加锁的时候也能保障线程安全
public class TestAtomicInteger {
static int b = 0;
public static void main(String[] args) throws InterruptedException {
AtomicInteger a = new AtomicInteger(0);
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
a.incrementAndGet();
b++;
}
});
t1.start();
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
a.incrementAndGet();
b++;
}
});
t2.start();
Thread.sleep(1000);
System.out.println("a=" + a);
System.out.println("b=" + b);
}
}
运行结果:
a=20000
b=16306
AtomicInteger对原子操作的常用方法
- addAndGet()- 以原子方式将给定值添加到当前值,并在添加后返回新值
- getAndAdd() - 以原子方式将给定值添加到当前值并返回旧值。
- incrementAndGet()- 以原子方式将当前值递增1并在递增后返回新值。它相当于i ++操作。
- getAndIncrement() - 以原子方式递增当前值并返回旧值。它相当于++ i 操作。
- decrementAndGet()- 原子地将当前值减1并在减量后返回新值。它等同于i-- 操作。
- getAndDecrement() - 以原子方式递减当前值并返回旧值。它相当于-- i 操作。
AtomicInteger底层原理(源码解析)
基于CAS的乐观锁实现
乐观锁是一种乐观思想,即认为每次取数据得时候都认为别的线程不会正在修改,所以不加锁,写数据的时候判断当前值与期望值是否相等,一样则更新,否则继续进行CAS操作。
unsafe是java提供的获得对对象内存地址访问的类,作用是在更新操作时提供“比较并替换”的作用,实际上就是AtomicInteger中的一个工具。
valueOffset是用来记录value本身在内存的编译地址的,也是为了更新操作在内存中找到value的位置。
unsafe提供了objectFieldOffset()方法用于获取某个字段相对Java对象的“起始地址”的偏移量,也提供了getInt、getLong、getObject之类的方法可以使用前面获取的偏移量来访问某个Java对象的某个字段。
注意:value是用来存储整数的时间变量,这里被声明为volatile,就是为了保证在更新操作时,当前线程可以拿到value最新的值(并发环境下,value可能已经被其他线程更新了)。
jdk1.8版本之前,AtomicIntege实现原子操作如下:
incrementAndGet
代码,先获取到当前的 value 属性值,然后将 value 加 1,赋值给一个局部的 next 变量,然而,这两步都是非线程安全的,但是内部有一个死循环,不断去做compareAndSet操作,直到成功为止,也就是修改的根本compareAndSet方法里面。
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
compareAndSet
代码:
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
compareAndSwapInt
代码,此方法为 native 方法,compareAndSwapInt 基于的是CPU 的 CAS指令来实现的。通过compareAndSwapInt方法,循环操作对传进来的旧值和新值进行对比和更新,两值不一致就进行更新操作,从而达到自增的结果。
publicfinal native boolean compareAndSwapInt(Object var1, long var2, int var4, intvar5);
在jdk1.8版本之后,AtomicInteger具体是如何实现的原子操作
jdk1.8封装了U.getAndAddInt()