java并发-AtomicInteger详解

发布时间:2023年12月28日


AtomicIntegerNumber类的一个子类,它还提供了很多的原子性的操作方法。

1.构造方法

/**
*创建
*AtomicInteger并且指定初始值,无参的AtomicInteger对象创建
*等价于AtomicInteger(0)。
**/
public AtomicInteger(int initialValue) {
value = initialValue;
}

/**
* 创建AtomicInteger的初始值为0。
*/
public AtomicInteger() {
}

2.Incremental(增加)操作

  • int getAndIncrement():返回当前int类型的value值,然后对value进行自增运算。
  • int incrementAndGet():直接返回自增后的结果,该操作方法能够确保对value的原子性增量操作。

3.Decremental(递减)操作

  • int getAndDecrement(): 返回当前int类型的value值,然后对value进行自减运算。
  • int decrementAndGet(): 直接返回自减后的结果,该操作方法能够确保对value的原子性减量操作。

4.原子性地更新value值

  • boolean compareAndSet(int expect, int update) :原子性地更新AtomicInteger的值,其中expect代表当前的AtomicInteger数值,update则是需要设置的新值,该方法会返回 一个boolean的结果:当expectAtomicInteger的当前值不相等时,修改会失败,返回值为false;若修改成功则会返回true
// 定义一个AtomicInteger类型的对象ai并且指定初值为10
AtomicInteger ai = new AtomicInteger(10);
// 调用compareAndSet方法,expect的值为100,修改肯定会失败
assert !ai.compareAndSet(100, 12);
// 修改并未成功,因此新值不等于12
assert ai.get() != 12;
// 执行了compareAndSet更新方法之后,ai的返回值依然为10,因为修改失败
assert ai.get() == 10;
// 调用compareAndSet方法,expect的值为10,修改成功(多线程情况下并不能
担保百分之百成功,// 关于这一点,在2.1.3节中会为大家讲解)
assert ai.compareAndSet(10, 12);
// 断言成功
assert ai.get() == 12;
  • int getAndAdd(int delta): 原子性地更新AtomicIntegervalue值,更新后的valuevaluedelta之和,方法的返回值为value的前一个值,该方法实际上是基于自旋+CAS算法实现的(Compare And Swap)原子性操作。
// 定义一个AtomicInteger类型的对象ai并且指定初始值为10
AtomicInteger ai = new AtomicInteger(10);
// 调用getAndAdd方法,返回value的前一个值为10
assert ai.getAndAdd(2) == 10;
// 调用get方法返回AtomicInteger的value值,当前返回值为12
assert ai.get() == 12;
  • int addAndGet(int delta): 该方法与getAndAdd(int delta) 一样,也是原子性地更新AtomicIntegervalue值,更新后的结果valuevaluedelta之和,但是该方法会立即返回更新后的value值。
// 定义一个AtomicInteger类型的对象ai并且指定初始值为10
AtomicInteger ai = new AtomicInteger(10);
// 调用addAndGet方法,返回当前value的值
assert ai.addAndGet(2)==12;
// 调用get方法返回AtomicInteger的value值,当前返回值为12
assert ai.get() == 12;

5.函数式接口

  • int getAndUpdate(IntUnaryOperator updateFunction): 原子性地更新AtomicInteger的值,方法入参为IntUnaryOperator接口,返回值为value更新之前的值。
// 定义一个AtomicInteger类型的对象ai并且指定初始值为10
AtomicInteger ai = new AtomicInteger(10);
// 调用getAndUpdate方法并且传入lambda表达式,返回结果为value的前一个值
assert ai.getAndUpdate(x -> x + 2) == 10;
// 调用get方法返回AtomicInteger的value值,当前返回值为12
assert ai.get() == 12;
  • int updateAndGet(IntUnaryOperator updateFunction): 原 子性地更新AtomicInteger的值,方法入参为IntUnaryOperator接口,该方法会立即返回更新后的value值。
// 定义一个AtomicInteger类型的对象ai并且指定初始值为10
AtomicInteger ai = new AtomicInteger(10);
// 调用updateAndGet方法并且传入lambda表达式,返回结果为value更新后的值
assert ai.updateAndGet(x -> x + 2) == 12;
// 调用get方法返回AtomicInteger的value值,当前返回值为12
assert ai.get() == 12;
  • int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction):原子性地更新AtomicInteger的值,方法入参为IntBinaryOperator接口和deltax,返回值为value更新之前的值。
// 定义一个AtomicInteger类型的对象ai并且指定初值为10
AtomicInteger ai = new AtomicInteger(10);
int result = ai.getAndAccumulate(5, Integer::sum);
assert result == 10;
assert ai.get() == 15;
  • int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction):该方法与getAndAccumulate类似,只不过会立即返回AtomicInteger的更新值。
// 定义一个AtomicInteger类型的对象ai并且指定初值为10
AtomicInteger ai = new AtomicInteger(10);
int result = ai.accumulateAndGet(5, Integer::sum);
assert result == 15;
assert ai.get() == 15;

6.其他方法

  • void set(int newValue):为value设置新值后其他线程就会立即看见。
  • void lazySet(int newValue):被强制刷新到主内存中,从而立即被其他线程看到。
  • int get(): 返回AtomicIntegervalue当前值。

7.源码分析

public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, v + delta));
    return v;
}

通过上边源码很容易看出底层实现是通过cas和自旋的操作。

8.使用示例

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerExample {
    public static void main(String[] args) {
        // 创建一个初始值为0的AtomicInteger
        AtomicInteger atomicInteger = new AtomicInteger(0);

        // 创建并启动两个增加线程
        Thread incrementThread1 = new Thread(new IncrementTask(atomicInteger));
        Thread incrementThread2 = new Thread(new IncrementTask(atomicInteger));

        incrementThread1.start();
        incrementThread2.start();

        try {
            // 等待两个线程执行完成
            incrementThread1.join();
            incrementThread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打印最终结果
        System.out.println("Final Value: " + atomicInteger.get());
    }

    // 自增任务
    static class IncrementTask implements Runnable {
        private AtomicInteger atomicInteger;

        public IncrementTask(AtomicInteger atomicInteger) {
            this.atomicInteger = atomicInteger;
        }

        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                // 使用原子操作自增
                atomicInteger.incrementAndGet();
            }
        }
    }
}

运行结果:

Final Value: 2000

9.总结

本文介绍了AtomicInteger相关的方法,通过源码很明显看出AtomicInteger底层是通过cas+自旋实现。

文章来源:https://blog.csdn.net/qq_36649893/article/details/135258017
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。