AtomicInteger介绍

    xiaoxiao2025-08-19  4

    内容引用: 原子变量(AtomicLong, AtomicInteger, AtomicReference) Java线程(十):CAS 无锁队列的实现

    概述

    一个提供原子操作的Integer的类。在Java语言中,++i和i++操作是“读-改-写”复合操作(在一个操作序列中,后一个操作依赖前一次操作的结果),在多线程并发处理的时候会出现问题,因为可能一个线程修改了变量,而另一个线程没有察觉到这样变化,所以并不是线程安全的。在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则将该操作变为原子操作。

    CAS (Compare And Swap)

    对内存中的共享数据进行操作的一种特殊指令,这个指令会对内存中的共享数据做原子的读写操作。操作过程:首先CPU会将内存中将要被更改的数据与期望的值作比较,当两个值相等时将内存中的数值更换为新值,否则不操作,最后返回旧值。即CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则返回V。这是一种乐观锁的思路,它相信在它修改之前,没有其他线程修改过;而Synchronized是一种悲观锁,它认为在它修改之前,一定会有其它线程去修改它,悲观锁效率很低。

    实现非阻塞式的原子性操作,但是会产生ABA问题,即:

    进程P1在共享变量中读到值为AP1被抢占了,进程P2执行P2把共享变量里的值从A改成了B,再改回到A,此时被P1抢占。P1回来看到共享变量里的值没有被改变,于是继续执行。 虽然P1以为变量值没有改变,继续执行了,但是这个会引发一些潜在的问题。AtomicInteger就是利用CAS实现原子性操作的。

    实现

    java.util.concurrent.atomic : Java并发包,是对Java部分数据类型的原子封装,在原有数据类型的基础上,提供了原子性的操作方法,保证了线程安全。

    //成员变量 (volatile,保证其内存可见性) private volatile int value; //部分成员方法 (全是final的) /* Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * @param expect the expected value * @param update the new value * @return true if successful. False return indicates that the actual value was not equal to the expected value.*/ // CAS实现 // 单线程下, compareAndSet返回永远为true; // 多线程下, 在将expect与最新的value(volatile的,可以实时看到最新值) 进行compare时, value可能被其他线程set了新值,而造成compare不相等,返回false。 public final boolean compareAndSet(int expect, int update) { // 比较并设置,这里利用Unsafe类的JNI方法实现,使用CAS指令,可以保证读-改-写是一个原子操作。 return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } // 获取当前的值,并自增 public final int getAndIncrement() { // 除非执行return语句否则一直循环程序体,重试到成功为止,保证能够线程安全地(原子的)改变当前值。 for (;;) { // 这样优于while(true) int current = get(); int next = current + 1; if (compareAndSet(current, next)) // 进行CAS操作 return current; } } // 获取当前的值,并加上预期的值 public final int getAndAdd(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return current; } }

    原理

    Volatile + CAS 具体见上面的注释。

    其他

    原子变量只能保证对一个变量的操作是原子的,如果有多个原子变量之间存在依赖的复合操作,也不可能是安全的。另外一种情况是要将更多的复合操作作为一个原子操作,则需要使用synchronized将要作为原子操作的语句包围起来。因为涉及到可变的共享变量(类实例成员变量)才会涉及到同步,否则不必使用synchronized。

    转载请注明原文地址: https://ju.6miu.com/read-1301867.html
    最新回复(0)