AtomicInteger

本文详细探讨了Java中的AtomicInteger类,包括其内部实现原理、原子操作特性及应用实例,揭示了如何利用AtomicInteger实现线程安全的计数器功能,以及其在并发编程中的优势。

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

package java.util.concurrent.atomic;
import sun.misc.Unsafe;

/**
 * 可以原子化的更新int值。
 * AtomicInteger可以用作程序中的计数器,但是不能作为Integer的替代品。
 * 尽管如此,AtomicInteger继承自Number,这允许它能统一的访问处理数字化类的tools和utilities。
 *
*/
public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // 使用Unsafe.compareAndSwapInt用于更新操作
    // 原子类都使用到了sun.misc.Unsafe,这个类的构造方法是私有的,另外,受Java Secutiry的限制,这个类只能被JDK信任的类实例化
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    // 内存中,value相对于this的地址偏移量,通过this的内存地址和这个偏移量可以获得value的内存地址
    private static final long valueOffset;

    static {
        try {
            //获取value字段的偏移量
            valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    // 以volatile定义value,保证其可见性
    private volatile int value;

    /**
     * 以给定的初始值创建一个新的AtomicInteger
     *
     * @param initialValue 初始值
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    /**
     * 以0作为初始值创建AtomicInteger
     */
    public AtomicInteger() {
    }

    /**
     * 获取当前值
     * value被volatile关键字修饰,所以线程每次都会重新读取这个值,而不是使用 本地副本
     *
     * @return 当前值
     */
    public final int get() {
        return value;
    }

    /**
     * 设置成给定的值
     * volatile提供了和synchronized相同的可见性,但是仅此而已,它只保证每次都能读到最新值
     * 当两个线程都读取了value的同一个值,然后做修改时,有一次update操作会被覆盖掉,这是因为读和写不是一个原子操作
     * 要使 volatile变量提供理想的线程安全,必须同时满足下面两个条件:
     * 1.对变量的写操作不依赖于当前值。
     * 2.该变量没有包含在具有其他变量的不变式中
     * 
     * 这里set正是基于第一条
     *
     * @param newValue 新值
     */
    public final void set(int newValue) {
        value = newValue;
    }

    /**
     * 最终设置成给定的值
     *
     * @param newValue 新值
     * @since 1.6
     */
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }

    /**
     * 设置给定的值,并返回老值,这是一个原子操作
     *
     * @param newValue 新值
     * @return 老值
     */
    public final int getAndSet(int newValue) {
        for (;;) {
            int current = get();
            if (compareAndSet(current, newValue))
                return current;
        }
    }

    /**
     * 原子化更新给定的值,在当前值和期望值相同时
     * Compare And Swap->比较并交换
     * CAS操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。
     * 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。
     * 
     * @param expect 期望值
     * @param update 新值
     * @return true 如果成功就返回true。返回false说明当前值和期望值不同
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 原子化更新给定的值,在当前值和期望值相同时
     *
     * 更新也许会不合逻辑的失败,不提供保证,在极少的情况下用于替代compareAndSet
     *
     * @param expect 期待值
     * @param update 新值
     * @return true 如果成功返回true
     */
    public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 原子递增并返回递增之前的值
     *
     * @return 递增之前的值
     */
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

    /**
     * 原子递减并返回递减之前的值
     *
     * @return 递减之前的值
     */
    public final int getAndDecrement() {
        for (;;) {
            int current = get();
            int next = current - 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

    /**
     * 原子相加并返回相加之前的值
     *
     * @param delta 要加的值
     * @return 相加之前的值
     */
    public final int getAndAdd(int delta) {
        for (;;) {
            int current = get();
            int next = current + delta;
            if (compareAndSet(current, next))
                return current;
        }
    }

    /**
     * 原子递增并返回递增后的值
     * i++这种操作看起来是一次操作,实际上可以分成读取i,加一,写回i这三步,所以它不是一个原子操作
     *
     * @return 递增后的值
     */
    public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

    /**
     * 原子递减并返回递减后的值
     * i--这种操作看起来是一次操作,实际上可以分成读取i,减一,写回i这三步,所以它不是一个原子操作
     *
     * @return 递减后的值
     */
    public final int decrementAndGet() {
        for (;;) {
            int current = get();
            int next = current - 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

    /**
     * 原子操作式地将加上给定的值
     *
     * @param delta 要加的值
     * @return 加完得到的结果
     */
    public final int addAndGet(int delta) {
        for (;;) {
            int current = get();
            int next = current + delta;
            if (compareAndSet(current, next))
                return next;
        }
    }

    /**
     * 返回当前值的字符串形式
     * @return 当前值的字符串形式
     */
    public String toString() {
        return Integer.toString(get());
    }


    public int intValue() {
        return get();
    }

    public long longValue() {
        return (long)get();
    }

    public float floatValue() {
        return (float)get();
    }

    public double doubleValue() {
        return (double)get();
    }

}
相关参考:
源码剖析之sun.misc.Unsafe
sun.misc.unsafe类的使用
JAVA CAS原理深度分析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值