21.jdk源码阅读之AtomicLong

1. 写在前面

AtomicLong 是 Java 中提供的一个用于处理高效并发编程的类。它提供了一些原子操作,确保在多线程环境下的安全性和高效性。按照惯例有几个问题大家看看有没有思考过:

  1. AtomicLong 和 Long 有什么区别?
  2. AtomicLong 的 compareAndSet 方法是如何工作的?
  3. 如何使用 AtomicLong 实现线程安全的计数器?
  4. AtomicLong 的优缺点是什么?
  5. AtomicLong 的 CAS 操作是如何保证线程安全的?

2. 全局视角

在这里插入图片描述

2.1 实现的接口

2.1.1 java.io.Serializable

使 AtomicLong 对象可以被序列化,以便在不同的 JVM 之间传输或持久化到存储中

2.1.2 java.lang.Number

使 AtomicLong 可以作为数值类型使用,并且可以与其他数值类型进行互操作

2.2 类的详细结构

2.2.1 内部字段

AtomicLong 使用一个 volatile 修饰的 long 字段来存储其值:

private volatile long value;

2.2.2 构造函数

AtomicLong 提供了两个构造函数:

  • 默认构造函数,初始值为 0:
public AtomicLong() {
    this.value = 0;
}
  • 带初始值的构造函数
public AtomicLong(long initialValue) {
    this.value = initialValue;
}

2.2.3 关键方法

  • long get(): 获取当前值。
public final long get() {
    return value;
}
  • void set(long newValue): 设置新值。
public final void set(long newValue) {
    value = newValue;
}
  • long getAndSet(long newValue): 获取当前值并设置新值。
public final long getAndSet(long newValue) {
    return UNSAFE.getAndSetLong(this, valueOffset, newValue);
}
  • boolean compareAndSet(long expect, long update): 如果当前值等于预期值,则原子地将其设置为新值。
public final boolean compareAndSet(long expect, long update) {
    return UNSAFE.compareAndSwapLong(this, valueOffset, expect, update);
}
  • long getAndIncrement(): 获取当前值并自增。
public final long getAndIncrement() {
    return getAndAdd(1);
}

  • long incrementAndGet(): 自增并获取新值。
public final long incrementAndGet() {
    return addAndGet(1);
}
  • long getAndDecrement(): 获取当前值并自减。
public final long getAndDecrement() {
    return getAndAdd(-1);
}
  • long decrementAndGet(): 自减并获取新值。
public final long decrementAndGet() {
    return addAndGet(-1);
}

  • long getAndAdd(long delta): 获取当前值并增加指定值。
public final long getAndAdd(long delta) {
    return UNSAFE.getAndAddLong(this, valueOffset, delta);
}
  • long addAndGet(long delta): 增加指定值并获取新值。
public final long addAndGet(long delta) {
    return UNSAFE.getAndAddLong(this, valueOffset, delta) + delta;
}

2.3 使用 Unsafe 类

AtomicLong 的实现依赖于 sun.misc.Unsafe 类来执行低级别的、硬件支持的原子操作。Unsafe 类提供了直接操作内存和执行原子操作的方法,这些方法通常是由 JVM 内部使用的。

例如,compareAndSet 方法使用 Unsafe 类的 compareAndSwapLong 方法来实现原子操作:

private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long valueOffset;

static {
    try {
        valueOffset = UNSAFE.objectFieldOffset(AtomicLong.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}

public final boolean compareAndSet(long expect, long update) {
    return UNSAFE.compareAndSwapLong(this, valueOffset, expect, update);
}

3. AtomicLong 和 Long 有什么区别?

  • AtomicLong 提供了原子操作,确保在多线程环境下的线程安全性。
  • Long 是不可变对象,不能在多线程环境下进行安全的更新操作。

4. AtomicLong 的 compareAndSet 方法是如何工作的?

compareAndSet 方法使用了硬件支持的原子指令(如 CAS,Compare-And-Swap)来实现。它的工作原理是:

  • 如果当前值等于预期值,则将其原子地更新为新值。
  • 如果当前值不等于预期值,则不更新,并返回 false。
AtomicLong atomicLong = new AtomicLong(100L);
boolean success = atomicLong.compareAndSet(100L, 200L); // 如果当前值是100L,则更新为200L

5. 如何使用 AtomicLong 实现线程安全的计数器?

可以使用 AtomicLong 实现线程安全的计数器,如下所示:

public class AtomicCounter {
    private AtomicLong counter = new AtomicLong();

    public void increment() {
        counter.incrementAndGet();
    }

    public long getValue() {
        return counter.get();
    }
}

6. AtomicLong 的优缺点是什么?

6.1 优点

  • 提供了高效的原子操作,避免了使用锁(如 synchronized)带来的性能开销。
  • 使用简单,线程安全。

6.2 缺点

  • 只能处理单一变量的原子操作,对于复杂的并发控制可能不够。
  • 在高竞争的情况下,CAS 操作可能会导致大量的重试,影响性能。

7. AtomicLong 与 LongAdder 有什么区别?

  • AtomicLong 使用 CAS 操作来保证线程安全,适用于低竞争的场景。
  • LongAdder 通过分段计数来减少竞争,适用于高竞争的场景。

8. AtomicLong 的 CAS 操作是如何保证线程安全的?

AtomicLong 的 CAS 操作(Compare-And-Swap)是由底层硬件支持的原子指令实现的。它的工作流程如下:

  1. 获取当前值。
  2. 比较当前值与预期值。
  3. 如果当前值等于预期值,则将其更新为新值。
  4. 如果当前值不等于预期值,则不更新,并返回 false。
    CAS 操作是原子的,即使在多线程环境下也能保证操作的完整性和一致性。

系列文章

1.JDK源码阅读之环境搭建

2.JDK源码阅读之目录介绍

3.jdk源码阅读之ArrayList(上)

4.jdk源码阅读之ArrayList(下)

5.jdk源码阅读之HashMap

6.jdk源码阅读之HashMap(下)

7.jdk源码阅读之ConcurrentHashMap(上)

8.jdk源码阅读之ConcurrentHashMap(下)

9.jdk源码阅读之ThreadLocal

10.jdk源码阅读之ReentrantLock

11.jdk源码阅读之CountDownLatch

12.jdk源码阅读之CyclicBarrier

13.jdk源码阅读之Semaphore

14.jdk源码阅读之线程池(上)

15.jdk源码阅读之线程池(下)

16.jdk源码阅读之ArrayBlockingQueue

17.jdk源码阅读之LinkedBlockingQueue

18.jdk源码阅读之CopyOnWriteArrayList

19.jdk源码阅读之FutureTask

20.jdk源码阅读之CompletableFuture

  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

至真源

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

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

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

打赏作者

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

抵扣说明:

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

余额充值