当前位置: 技术文章>> 100道Java面试题之-Java中的原子类(如AtomicInteger)是如何实现线程安全的?

文章标题:100道Java面试题之-Java中的原子类(如AtomicInteger)是如何实现线程安全的?
  • 文章分类: 后端
  • 5489 阅读

Java中的原子类(如AtomicInteger)通过底层使用CAS(Compare-And-Swap,即比较并交换)操作来实现线程安全。CAS操作是原子操作,它包含三个参数:内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。这是硬件级别的支持,因此在执行时不会被线程调度机制中断。

原子类实现线程安全的关键点:

  1. CAS操作

    • AtomicInteger内部使用volatile int变量来存储当前值,确保所有线程都能看到最新的值。
    • 使用CAS操作来更新这个值。例如,在AtomicIntegerincrementAndGet()方法中,CAS操作会尝试将当前值增加1。如果在此期间没有其他线程修改过这个值,则操作成功;如果有其他线程修改了值,则CAS操作失败,当前线程会重新尝试,直到成功为止。
  2. 自旋锁

    • 当CAS操作失败时,原子类内部会进行重试,这个过程称为自旋锁。自旋锁避免了线程在CPU之间的切换开销,因为它让线程保持活动状态,等待锁被释放。
    • 然而,自旋锁在锁持有时间较长的情况下可能会浪费CPU资源,因为线程会持续进行无用的循环检查。
  3. 无锁编程

    • 原子类实现了无锁编程(Lock-Free Programming),这意味着它们不使用传统的锁(如synchronized关键字或Lock接口)来同步对共享资源的访问。
    • 无锁编程通常基于乐观并发策略,即假设冲突不会经常发生,从而减少了锁的开销。

示例代码:

AtomicInteger atomicInteger = new AtomicInteger(0);

// 线程安全地增加
int newValue = atomicInteger.incrementAndGet();

// 原子地更新,只有当当前值等于expected值时
boolean updated = atomicInteger.compareAndSet(expectedValue, newValue);

总结:

Java中的原子类通过CAS操作、自旋锁和无锁编程技术来实现线程安全。这些类提供了比传统锁更高的并发级别,并且减少了线程切换的开销,但也可能在高冲突情况下导致CPU资源的浪费。在设计高并发系统时,合理使用原子类可以帮助开发者编写出既高效又安全的并发代码。

推荐文章