java并发-AtomicInteger详解

文章目录


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

1.构造方法

java 复制代码
/**
*创建
*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
java 复制代码
// 定义一个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)原子性操作。
java 复制代码
// 定义一个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值。
java 复制代码
// 定义一个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更新之前的值。
java 复制代码
// 定义一个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值。
java 复制代码
// 定义一个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更新之前的值。
java 复制代码
// 定义一个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的更新值。
java 复制代码
// 定义一个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.源码分析

java 复制代码
public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
java 复制代码
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.使用示例

java 复制代码
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();
            }
        }
    }
}

运行结果:

java 复制代码
Final Value: 2000

9.总结

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

相关推荐
qzhqbb17 分钟前
基于统计方法的语言模型
人工智能·语言模型·easyui
冷眼看人间恩怨42 分钟前
【话题讨论】AI大模型重塑软件开发:定义、应用、优势与挑战
人工智能·ai编程·软件开发
2401_8830410843 分钟前
新锐品牌电商代运营公司都有哪些?
大数据·人工智能
奋斗的小花生1 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功1 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2341 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨1 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程1 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
AI极客菌2 小时前
Controlnet作者新作IC-light V2:基于FLUX训练,支持处理风格化图像,细节远高于SD1.5。
人工智能·计算机视觉·ai作画·stable diffusion·aigc·flux·人工智能作画
阿_旭2 小时前
一文读懂| 自注意力与交叉注意力机制在计算机视觉中作用与基本原理
人工智能·深度学习·计算机视觉·cross-attention·self-attention