AtomicInteger有关自旋锁的原子性问题

本文探讨了AtomicInteger如何利用CAS(Compare and Swap)自旋锁在不使用synchronized的情况下实现线程安全的自增操作。通过分析incrementAndGet()方法的源码,展示了getAndAddInt()方法中的CAS操作过程,解释了在多线程环境下如何避免原子性问题。虽然CAS有两个步骤(比较和修改),但在HotSpot虚拟机的底层支持下,操作系统确保了这一操作的原子性,从而保证了并发安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AtomicInteger

    public static void main(String[] args) {
        AtomicInteger ai = new AtomicInteger(20);
        System.out.println(ai.incrementAndGet());
    }

        在学习AtominInteger时,第一次接触了CAS,也就是在自增的时候使用CAS自旋锁解决并发问题。调用的方法时incrementAndGet方法。而这个自增的操作本质上不是一个原子性操作,但是改方法在没有加synchronized的情况下实现了线程安全。下面深入学习CAS:

    /**
     * Atomically increments by one the current value.
     *  以原子性的方法,将当前值+1
     * @return the updated value
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

        这里用到了unsafe变量,该变量比较重要,以后解答,先看getAndAddInt方法

    //操作源码,传入三个值,V,A,B,第一个V是AtomicInteger维护的变量value,表示当前数的实际值,他被volatile修饰来保证其可见性。第二个值A为当前希望操作的值,B为当前希望修改后的值。
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
​
        return var5;
    }

        整个CAS被三个值主导:V,A,B。首先CAS,compareAndSet方法将A与实际值V进行比对,如果相等,那么就可以操作修改为B,如果不等那就放弃操作。

        这样保证了修改的一致性,但是不能保证修改的原子性,因为他有两个操作,一个是比对,第二个是修改。假设现在线程1需要将value = 1修改为2,那么比对A=1和V=1,发现相同那么修改。此时线程2比对A=1和V=1,发现也相同,把V修改为3。线程2执行完毕,而在线程1中,此时的V已经是3了,但是线程1已经经历过了比对操作,将3又修改为了2,这样就造成了严重的原子性问题。

        这里是基于HotSpot底层调用操作系统来完成原子性操作的,在操作系统执行比对并修改的CAS操作时,加上了底层锁,保证了操作原子性,而我们使用Java的时候全然不知。

### 原子变量 原子变量是指那些能够执行不可分割(即原子性)操作的对象。这些操作要么完全被执行,要么根本不被执行,在线程环境中确保了数据的一致性和安全性[^1]。 对于原子变量的支持通常是通过特定的机器指令来实现,比如比较并交换(compare-and-swap, CAS),这类底层硬件级别的支持使得个处理器核心可以安全地访问同一个内存位置而不用担心竞争条件的发生[^2]。 #### 使用场景 - 需要高效处理高并发情况下的简单数值更新或者状态标记的情况。 - 实现更复杂的同步原语的基础构建模块,如无队列或其他高级并发数据结构。 ```java AtomicInteger atomicInt = new AtomicInteger(0); atomicInt.incrementAndGet(); // 安全地增加整型值 ``` ### 自旋锁 自旋锁是一种特殊的定机制,当一个线程尝试获取已被占用的资源时并不会立即进入等待状态而是不断循环检查直到该资源可用为止。这种方式适用于持有时间非常短的情景下减少上下文切换带来的额外负担。 由于其特性决定了只有在预期占有时间为极短时间内才适合采用此方法;如果预计会有较长的时间无法获得,则应考虑其他类型的方案以防止浪费过CPU周期。 ```c spin_lock(&lock); /* 获取自旋锁 */ /* 执行临界区代码 */ spin_unlock(&lock); /* 释放自旋锁 */ ``` ### 区别与联系 两者都是为了应对线程环境中的资源共享问题所设计的不同层次上的解决方案: - **区别** - 原子变量主要针对的是单一对象上基本操作的安全保障; - 自旋锁则是用来保护更大范围内的代码片段——所谓的“临界区”,其中可能涉及个变量之间的复杂交互逻辑。 - **联系** - 在某些情况下,可以通过组合使用这两种工具达到更好的效果。例如,利用原子变量作为内部计数器帮助管理外部可见的状态变化,同时依靠自旋锁协调不同线程间对该共享资源的竞争关系。 ### 并发控制 无论是原子变量还是自旋锁都属于并发编程领域的重要组成部分,它们共同作用于提高程序运行效率的同时也增加了开发难度。合理选择合适的同步方式取决于具体应用场景的需求分析以及对系统整体架构的理解程度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aristocrat l

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值