Bootstrap

并发编程面试题1

一、原子性高频问题:

1.1 Java中如何实现线程安全?

多线程操作共享数据会出现问题。可以使用锁来解决:

  • 悲观锁: 使用 synchronizedLock
  • 乐观锁: 使用 CAS(Compare-And-Swap)

可以根据业务情况选择 ThreadLocal,让每个线程处理自己的数据。

1.2 CAS底层实现

回答思路: 先解释比较和交换的概念,在Java层面讨论native方法,再深入到C++中的 cmpxchg 指令,最后谈到 lock 指令保证 cmpxchg 的原子性。

在Java中,CAS(Compare-And-Swap)在Java层面可以看到 Unsafe 类中的native方法。

基本操作步骤:

  • 比较当前值与预期值是否一致,如果一致,交换并返回 true
  • 如果不一致,不交换并返回 false

可以查看 Unsafe 类中提供的CAS操作,有四个参数:对象、属性的内存偏移量、旧值和新值。

在这里插入图片描述

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

CAS的底层实现涉及到 cmpxchg 指令。在多核系统中,需要 lock 指令来保证 cmpxchg 的原子性。

  • cmpxchg 是一个汇编指令,支持比较和交换操作。
  • cmpxchg 本身不保证原子性,所以需要 lock 指令。
  • lock 指令在CPU层面相当于一个锁,通常粒度是缓存行级别,有时是总线锁,但成本较高。

1.3 CAS的常见问题

  • ABA问题: ABA问题不一定是问题。例如,仅有++,–的操作,不会影响结果。解决方案是使用带版本号的CAS,如 AtomicStampedReference
    在这里插入图片描述

  • 自旋次数过多: 自旋次数过多会消耗大量的CPU资源。解决方法:

    • synchronized 方向:CAS多次失败后,将线程挂起,避免占用过多CP
;