AtomicInteger

1. 前言

AtomicInteger是Java中的一个原子整数类,它提供了一种在多线程环境下进行原子性操作的方法。所谓原子性操作是指不会被线程调度机制打断的操作;这些操作可以在可能被其他线程影响的情况下作为一个不可分割的整体执行。

在并发编程中,如果多个线程同时对同一个变量进行读取和写入操作,会存在竞态条件(Race Condition),导致数据不一致或错误。为了解决这种问题,Java提供了一系列的原子类,其中包括AtomicInteger。

AtomicInteger可以保证对整型变量的操作是原子性的,比如增加、减少操作。它使用了底层的CAS(Compare and Swap)操作来实现原子性。

2. 介绍CAS

AtomicInteger的实现依赖于底层的CAS(Compare-And-Swap)操作,确保其操作是原子性的。CAS是一种硬件级别的原子操作,通常由处理器直接支持,它可以在多线程环境中保证对变量的修改不会引起竞态条件。

CAS 操作

CAS 操作涉及三个值:

  1. 内存位置(V):需要读取和更新的变量。
  2. 预期值(A):当前线程认为变量应该持有的值。
  3. 新值(B):线程希望将变量的值更新为的新值。

CAS 过程如下:

  • 检查内存位置 V 的当前值是否等于预期值 A。
  • 如果相等,则将内存位置 V 的值更新为新值 B。
  • 如果不相等,则不进行任何操作并返回当前值。

这个过程是一个原子操作,不会被其他线程中断。

AtomicInteger 实现原理

在 Java 中,AtomicInteger 类使用 CAS 操作来实现其方法。以下是它的一些关键方法及其实现原理:

incrementAndGet()

这是 AtomicInteger 类中一个常用方法,用于以原子方式将当前值加 1,并返回加 1 后的值。

java 复制代码
public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

解释:

  1. 获取当前值 :调用 get() 方法获取当前值。
  2. 计算下一个值:将当前值加 1,得到下一个值。
  3. CAS 操作 :调用 compareAndSet(current, next) 尝试将当前值更新为下一个值。
    • 如果当前值等于预期值(current),则更新成功,返回更新后的值。
    • 如果当前值不等于预期值,则表示在这段时间内已经有其他线程修改了当前值。因此,循环重试,直到更新成功。
compareAndSet(int expect, int update)

这是一个本地方法(native),通常由 JVM 底层通过硬件指令实现。

java 复制代码
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

解释:

  1. unsafe :使用了 Unsafe 类,这是一个提供底层操作的类。Unsafe 类允许进行低级别的、不受限制的内存操作。
  2. compareAndSwapInt:这是一个本地方法,使用底层的硬件指令来执行 CAS 操作。

为什么 AtomicInteger 是原子的

由上述实现原理可以看出,AtomicInteger 的操作是原子的,原因主要有以下几点:

  1. CAS 操作:底层的 CAS 操作保证了整个比较和交换步骤的原子性。
  2. 硬件支持:现代处理器通常提供对 CAS 操作的原生支持,这样可以确保这些操作在硬件级别上是原子的。
  3. 循环重试:如果 CAS 操作失败(因为其他线程修改了值),AtomicInteger 会自动进行循环重试,直到操作成功。

因此,AtomicInteger 能够在多线程环境中安全地进行整数操作,避免传统锁机制带来的性能损耗,同时确保操作的正确性。

相关推荐
蔡俊锋5 分钟前
Javar如何用RabbitMQ订单超时处理
java·python·rabbitmq·ruby
天天摸鱼的java工程师22 分钟前
Snowflake 雪花算法优缺点(Java老司机实战总结)
java·后端·面试
Miraitowa_cheems1 小时前
LeetCode算法日记 - Day 11: 寻找峰值、山脉数组的峰顶索引
java·算法·leetcode
海梨花1 小时前
【从零开始学习Redis】项目实战-黑马点评D2
java·数据库·redis·后端·缓存
共享家95271 小时前
linux-高级IO(上)
java·linux·服务器
橘子郡1231 小时前
观察者模式和发布订阅模式对比,Java示例
java
指针满天飞1 小时前
Collections.synchronizedList是如何将List变为线程安全的
java·数据结构·list
Java技术小馆1 小时前
重构 Controller 的 7 个黄金法则
java·后端·面试
金銀銅鐵1 小时前
[Java] 以 IntStream 为例,浅析 Stream 的实现
java·后端
曳渔2 小时前
UDP/TCP套接字编程简单实战指南
java·开发语言·网络·网络协议·tcp/ip·udp