Android AtomicInteger使用

本文深入解析了AtomicInteger类的使用和内部实现,介绍了其在多线程环境下如何保证整型数值的原子操作,包括自动增减、流水号生成等功能。探讨了AtomicInteger与其他同步数值类的区别,以及其提供的核心方法如get()、set()、getAndIncrement()等。

AtomicInteger使用

  • 多个线程访问同一个整型数值;
  • 自动增加/减小值;
  • 经常作为流水值使用;
  • 线程安全,使用原子锁;
  • 包名 java.util.concurrent.atomic, 该包名下包含其它同步数值类 AtomicBooleanAtomicLong等;
  • 常用方法:get()set()getAndIncrement()getAndDecrement()

AtomicInteger源码

/**
 * An {@code int} value that may be updated atomically.  See the
 * {@link java.util.concurrent.atomic} package specification for
 * description of the properties of atomic variables. An
 * {@code AtomicInteger} is used in applications such as atomically
 * incremented counters, and cannot be used as a replacement for an
 * {@link java.lang.Integer}. However, this class does extend
 * {@code Number} to allow uniform access by tools and utilities that
 * deal with numerically-based classes.
 *
 * @since 1.5
 * @author Doug Lea
 */
public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
    private static final long VALUE;

    static {
        try {
            VALUE = U.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (ReflectiveOperationException e) {
            throw new Error(e);
        }
    }

    private volatile int value;

    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    /**
     * Creates a new AtomicInteger with initial value {@code 0}.
     */
    public AtomicInteger() {
    }

    /**
     * Gets the current value.
     *
     * @return the current value
     */
    public final int get() {
        return value;
    }

    /**
     * Sets to the given value.
     *
     * @param newValue the new value
     */
    public final void set(int newValue) {
        value = newValue;
    }

    /**
     * Eventually sets to the given value.
     *
     * @param newValue the new value
     * @since 1.6
     */
    public final void lazySet(int newValue) {
        U.putOrderedInt(this, VALUE, newValue);
    }

    /**
     * Atomically sets to the given value and returns the old value.
     *
     * @param newValue the new value
     * @return the previous value
     */
    public final int getAndSet(int newValue) {
        return U.getAndSetInt(this, VALUE, newValue);
    }

    /**
     * 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 {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(int expect, int update) {
        return U.compareAndSwapInt(this, VALUE, expect, update);
    }

    /**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * <p><a href="package-summary.html#weakCompareAndSet">May fail
     * spuriously and does not provide ordering guarantees</a>, so is
     * only rarely an appropriate alternative to {@code compareAndSet}.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful
     */
    public final boolean weakCompareAndSet(int expect, int update) {
        return U.compareAndSwapInt(this, VALUE, expect, update);
    }

    /**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
    public final int getAndIncrement() {
        return U.getAndAddInt(this, VALUE, 1);
    }

    /**
     * Atomically decrements by one the current value.
     *
     * @return the previous value
     */
    public final int getAndDecrement() {
        return U.getAndAddInt(this, VALUE, -1);
    }

    /**
     * Atomically adds the given value to the current value.
     *
     * @param delta the value to add
     * @return the previous value
     */
    public final int getAndAdd(int delta) {
        return U.getAndAddInt(this, VALUE, delta);
    }

    /**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        return U.getAndAddInt(this, VALUE, 1) + 1;
    }

    /**
     * Atomically decrements by one the current value.
     *
     * @return the updated value
     */
    public final int decrementAndGet() {
        return U.getAndAddInt(this, VALUE, -1) - 1;
    }

    /**
     * Atomically adds the given value to the current value.
     *
     * @param delta the value to add
     * @return the updated value
     */
    public final int addAndGet(int delta) {
        return U.getAndAddInt(this, VALUE, delta) + delta;
    }

    /**
     * Atomically updates the current value with the results of
     * applying the given function, returning the previous value. The
     * function should be side-effect-free, since it may be re-applied
     * when attempted updates fail due to contention among threads.
     *
     * @param updateFunction a side-effect-free function
     * @return the previous value
     * @since 1.8
     */
    public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    /**
     * Atomically updates the current value with the results of
     * applying the given function, returning the updated value. The
     * function should be side-effect-free, since it may be re-applied
     * when attempted updates fail due to contention among threads.
     *
     * @param updateFunction a side-effect-free function
     * @return the updated value
     * @since 1.8
     */
    public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

    /**
     * Atomically updates the current value with the results of
     * applying the given function to the current and given values,
     * returning the previous value. The function should be
     * side-effect-free, since it may be re-applied when attempted
     * updates fail due to contention among threads.  The function
     * is applied with the current value as its first argument,
     * and the given update as the second argument.
     *
     * @param x the update value
     * @param accumulatorFunction a side-effect-free function of two arguments
     * @return the previous value
     * @since 1.8
     */
    public final int getAndAccumulate(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    /**
     * Atomically updates the current value with the results of
     * applying the given function to the current and given values,
     * returning the updated value. The function should be
     * side-effect-free, since it may be re-applied when attempted
     * updates fail due to contention among threads.  The function
     * is applied with the current value as its first argument,
     * and the given update as the second argument.
     *
     * @param x the update value
     * @param accumulatorFunction a side-effect-free function of two arguments
     * @return the updated value
     * @since 1.8
     */
    public final int accumulateAndGet(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSet(prev, next));
        return next;
    }

    /**
     * Returns the String representation of the current value.
     * @return the String representation of the current value
     */
    public String toString() {
        return Integer.toString(get());
    }

    /**
     * Returns the value of this {@code AtomicInteger} as an {@code int}.
     * Equivalent to {@link #get()}.
     */
    public int intValue() {
        return get();
    }

    /**
     * Returns the value of this {@code AtomicInteger} as a {@code long}
     * after a widening primitive conversion.
     * @jls 5.1.2 Widening Primitive Conversions
     */
    public long longValue() {
        return (long)get();
    }

    /**
     * Returns the value of this {@code AtomicInteger} as a {@code float}
     * after a widening primitive conversion.
     * @jls 5.1.2 Widening Primitive Conversions
     */
    public float floatValue() {
        return (float)get();
    }

    /**
     * Returns the value of this {@code AtomicInteger} as a {@code double}
     * after a widening primitive conversion.
     * @jls 5.1.2 Widening Primitive Conversions
     */
    public double doubleValue() {
        return (double)get();
    }

}
<think>我们正在讨论Android开发中的锁选择问题。在Android开发中,我们经常需要处理多线程同步问题,而选择合适的锁机制至关重要。根据Android系统的特性和开发需求,我们可以考虑以下几种锁: 1. **synchronized关键字**:这是Java中最基本的锁,适用于简单的同步场景。在Android中,它同样有效,但需要注意避免过度使用导致性能问题。 2. **ReentrantLock**:这是java.util.concurrent.locks包中的锁,提供了比synchronized更灵活的操作,比如可中断、可超时、公平锁等。 3. **ReentrantReadWriteLock**:当读写操作分离时,这种锁可以提高并发性能,允许多个读操作同时进行,但写操作独占。 4. **StampedLock**:在API 24(Android 7.0)及以上引入,是一种更高效的读写锁,通过乐观读模式进一步提升性能。 5. **Handler/Looper机制**:在Android中,我们通常使用Handler将任务切换到主线程执行,这本身也是一种同步机制,避免多线程问题。 ### 最佳锁类型选择建议 1. **简单同步场景**:如果只是简单的代码块同步,使用`synchronized`关键字即可,因为它简洁且不易出错。例如: ```java public class Example { private int count = 0; public synchronized void increment() { count++; } } ``` 2. **需要灵活控制的场景**:如果需要尝试获取锁、超时或中断,使用`ReentrantLock`。例如: ```java ReentrantLock lock = new ReentrantLock(); if (lock.tryLock(1, TimeUnit.SECONDS)) { try { // 操作共享资源 } finally { lock.unlock(); } } ``` 3. **读写分离场景**:当读操作远多于写操作时,使用`ReentrantReadWriteLock`或`StampedLock`(如果支持API 24+)。例如: ```java ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); // 读锁 lock.readLock().lock(); try { // 读操作 } finally { lock.readLock().unlock(); } // 写锁 lock.writeLock().lock(); try { // 写操作 } finally { lock.writeLock().unlock(); } ``` 4. **高性能读写场景(API 24+)**:使用`StampedLock`,尤其是乐观读模式: ```java StampedLock lock = new StampedLock(); long stamp = lock.tryOptimisticRead(); // 读操作 if (!lock.validate(stamp)) { stamp = lock.readLock(); try { // 重新读操作 } finally { lock.unlockRead(stamp); } } ``` 5. **UI线程同步**:在Android中,更新UI必须回到主线程,使用`Handler`或`runOnUiThread`: ```java new Handler(Looper.getMainLooper()).post(() -> { // 更新UI }); ``` ### 注意事项 - **避免死锁**:确保锁的获取和释放成对出现,尽量在finally块中释放锁。 - **性能考虑**:锁的粒度要尽可能小,减少同步区域的大小。 - **Android版本兼容**:如`StampedLock`仅支持API 24及以上,需注意兼容性。 ### 总结 在Android开发中,没有绝对最佳的锁类型,而是根据具体场景选择: - 简单同步:`synchronized` - 复杂控制:`ReentrantLock` - 读写分离:`ReentrantReadWriteLock`或`StampedLock`(高版本) - UI同步:`Handler`/`Looper` 此外,还可以考虑使用`Atomic`类(如`AtomicInteger`)进行无锁编程,这在某些场景下性能更高[^4]。 §§相关问题§§ 1. 如何在Android中避免死锁? 2. 无锁编程在Android中有哪些应用? 3. 如何选择ReentrantLock和synchronized? 4. 在Android中如何实现线程安全的数据结构?</think>在 Android 开发中,选择最佳锁类型需要根据具体场景和性能需求进行权衡。以下是各类锁的对比分析和推荐方案: ### 1. 基础锁类型对比 | **锁类型** | **适用场景** | **优点** | **缺点** | **推荐指数** | |----------------------|----------------------------------|----------------------------------|----------------------------------|-------------| | `synchronized` | 简单同步场景 | 语法简单,自动释放锁 | 功能有限,不支持超时 | ⭐⭐⭐⭐ | | `ReentrantLock` | 需要精细控制的复杂同步 | 支持公平锁/非公平锁、可中断、超时 | 需手动释放,代码复杂度高 | ⭐⭐⭐⭐⭐ | | `ReentrantReadWriteLock` | 读多写少场景 | 读写分离提高并发性能 | 写锁饥饿风险 | ⭐⭐⭐⭐ | | `StampedLock` (API 24+) | 极高并发读写场景 | 乐观读锁提升性能 | 复杂易错,不支持重入 | ⭐⭐⭐ | ### 2. 最佳实践方案 #### (1) **常规同步场景:`synchronized`** ```java public class Counter { private int count = 0; // 方法级同步 public synchronized void increment() { count++; } // 代码块同步 public void safeOperation() { synchronized(this) { // 临界区操作 } } } ``` > ✅ 适用:简单对象同步、单例模式实现 > ❌ 避免:嵌套锁(易死锁) #### (2) **高级控制场景:`ReentrantLock`** ```java ReentrantLock lock = new ReentrantLock(true); // 公平锁 void performTask() { try { if (lock.tryLock(100, TimeUnit.MILLISECONDS)) { // 超时控制 // 临界区操作 } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); // 必须手动释放[^4] } } } ``` > ✅ 适用:需要超时/中断控制的网络请求、复杂事务 > 💡 技巧:结合`Condition`实现精准唤醒 #### (3) **读多写少场景:`ReentrantReadWriteLock`** ```java ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); int getData() { rwLock.readLock().lock(); try { return sharedData; // 并发读 } finally { rwLock.readLock().unlock(); } } void updateData() { rwLock.writeLock().lock(); try { // 独占写 } finally { rwLock.writeLock().unlock(); } } ``` > ✅ 适用:配置数据缓存、日志系统等读密集型操作 #### (4) **高性能场景:`StampedLock` (Android 7.0+)** ```java StampedLock sl = new StampedLock(); // 乐观读 long stamp = sl.tryOptimisticRead(); int value = sharedValue; if (!sl.validate(stamp)) { stamp = sl.readLock(); // 升级为悲观读 try { value = sharedValue; } finally { sl.unlockRead(stamp); } } ``` ### 3. 选择原则 1. **简单优先**:90%场景用`synchronized`足够 2. **避免死锁**:按固定顺序获取多个锁 3. **性能敏感**:读多写少用`ReadWriteLock`,极高并发用`StampedLock` 4. **生命周期**:在`onDestroy()`中释放所有锁资源 ### 4. 特殊场景方案 - **UI线程同步**:使用`Handler`/`runOnUiThread` ```java new Handler(Looper.getMainLooper()).post(() -> { // 主线程安全操作 }); ``` - **原子操作**:优先使用`AtomicInteger`等原子类 - **跨进程通信**:使用`Binder`或`AIDL`的同步机制[^1] > ⚠️ 注意:避免在锁内执行耗时操作(如网络请求),否则会引发ANR[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值