当前位置:首页 > Java > 正文

Java并发利器:AtomicLong详解(小白也能轻松掌握线程安全的原子操作)

Java并发编程 中,如何保证多个线程对共享变量的操作是线程安全的?传统的解决方案是使用 synchronized 关键字或 ReentrantLock,但这些方式存在性能开销。而 Java 提供了更高效的替代方案——java.util.concurrent.atomic 包中的原子类,其中 AtomicLong 就是最常用的一种。

Java并发利器:AtomicLong详解(小白也能轻松掌握线程安全的原子操作) AtomicLong  Java并发编程 原子操作 线程安全 第1张

什么是 AtomicLong?

AtomicLong 是 Java 提供的一个线程安全的长整型(long)包装类。它通过底层的 CAS(Compare-And-Swap) 机制实现原子操作,无需加锁即可保证多线程环境下的数据一致性。

与普通 long 变量不同,AtomicLong 的所有操作(如 get、set、incrementAndGet 等)都是原子性的,这意味着即使多个线程同时访问,也不会出现数据错乱。

为什么需要 AtomicLong?

假设我们有一个计数器,在多线程环境下频繁递增:

// 非线程安全的写法public class UnsafeCounter {    private long count = 0;    public void increment() {        count++; // 实际上是 read-modify-write 三步操作    }    public long getCount() {        return count;    }}

上面的 count++ 看似一行代码,实则包含三个步骤:读取当前值 → 加1 → 写回新值。如果多个线程同时执行,就可能发生竞态条件(Race Condition),导致结果不准确。

AtomicLong 的基本用法

使用 AtomicLong 非常简单,只需导入并创建实例即可:

import java.util.concurrent.atomic.AtomicLong;public class SafeCounter {    private AtomicLong count = new AtomicLong(0);    public void increment() {        count.incrementAndGet(); // 原子性自增    }    public long getCount() {        return count.get();    }}

这里 incrementAndGet() 方法会原子性地将值加1并返回新值,完全避免了竞态条件。

常用方法一览

  • get():获取当前值
  • set(long newValue):设置新值(非原子比较,但写入是原子的)
  • getAndSet(long newValue):先获取旧值,再设置新值
  • incrementAndGet():自增1并返回新值
  • getAndIncrement():返回当前值,然后自增1
  • addAndGet(long delta):加上指定值并返回新值
  • compareAndSet(long expectedValue, long newValue):如果当前值等于期望值,则更新为新值(核心 CAS 操作)

实战示例:多线程计数器

下面是一个完整的多线程测试,对比普通 long 和 AtomicLong 的结果:

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.atomic.AtomicLong;public class AtomicLongDemo {    private static final int THREADS = 10;    private static final int INCREMENTS = 10000;    // 非线程安全计数器    static long unsafeCount = 0;    // 线程安全计数器    static AtomicLong safeCount = new AtomicLong(0);    public static void main(String[] args) throws InterruptedException {        ExecutorService executor = Executors.newFixedThreadPool(THREADS);        // 启动多个线程进行自增        for (int i = 0; i < THREADS; i++) {            executor.submit(() -> {                for (int j = 0; j < INCREMENTS; j++) {                    unsafeCount++;           // 不安全                    safeCount.incrementAndGet(); // 安全                }            });        }        executor.shutdown();        while (!executor.isTerminated()) {            Thread.sleep(100);        }        System.out.println("Unsafe count: " + unsafeCount);        System.out.println("Safe count:   " + safeCount.get());    }}

运行多次你会发现:unsafeCount 的结果通常小于 100000(10线程 × 10000次),而 safeCount 始终是准确的 100000。这充分体现了 AtomicLong 在线程安全场景下的可靠性

性能优势与适用场景

AtomicLong 基于硬件级别的 CAS 指令,避免了锁的开销,因此在高并发、低竞争场景下性能远优于 synchronized。

适用场景包括:

  • 计数器(如访问量统计)
  • 生成唯一ID
  • 状态标志位的更新
  • 无锁数据结构的构建

注意事项

虽然 AtomicLong 高效,但也有局限:

  • 在高竞争(大量线程频繁修改同一变量)时,CAS 可能因不断重试而性能下降;
  • 不能替代复杂的同步逻辑(如需要多个变量一起更新);
  • Java 8 引入了 LongAdder,在极高并发计数场景下性能更好。

总结

通过本教程,你已经掌握了 AtomicLong 的核心概念、基本用法和适用场景。作为 Java并发编程 中的重要工具,它能帮助你在不使用锁的情况下实现高效、安全的原子操作。无论是开发高性能服务器、中间件,还是日常业务系统,理解并善用 AtomicLong 都是提升代码质量的关键一步。

记住:在多线程世界里,“看似简单”的操作往往暗藏玄机,而 AtomicLong 正是你守护数据一致性的得力助手!