AtomicInteger定义

  1. AtomicInteger类是系统底层保护的int类型,通过对int类型的数据进行封装,提供执行方法的控制进行值的原子操作,但AtomicInteger ≠ Integer。
  2. AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。


AtomicInteger使用场景

  1. AtomicInteger提供原子操作来进行Integer的使用,适合高并发情况下的使用。
  2. 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()