Java并发

74 阅读2分钟
mindmap
      JUC
          原子类
            AtomicInteger
            AtomicReference
          并发队列
            LinkedBlockingQueue
            ArrayBlockingQueue
            ConcurrentLinkedDeque
            ConcurrentLinkedQueue
          同步工具
            CountDownLatch
            Semaphore
            CyclicBarrier
            Exchanger
          并发集合
            ConcurrentHashMap
            CopyOnWriteArrayList
            CopyOnWriteArraySet
            ConcurrentSkipListMap
          并发锁
            ReentrantLock
            ReentrantReadWriteLock
          线程池
            Executor
            Fork/Join
    

原子类

1.Java原子类的实现原理

Java原子类主要依赖CAS(Compare and Swap)操作和volatile变量,通过无锁编程实现线程安全。

核心机制(CAS)

  • 定义:CAS是一种硬件支持的原子操作,通过比较内存与预期值,若匹配则更新为新值。
  • 操作语义:
boolean CAS(address, expectedValue, newValue) {
    if (*address == expectedValue) {
        *address = newValue;
        return true;
    }
    return false;
}
  • 硬件支持:通过CPU指令(如x86的Lock CMPXHG)实现原子类。

2.原子类的实现步骤

  1. 使用volatile保证可见性(如AtomicInteger的value)会用volatile修饰:
public class AtomicInteger{
    //作用:确保每次读取到最新值,避免脏读
    private volatile int value;
}
  1. 通过Unsafe类调用底层CAS
  • Unsafe类:提供直接操作内存和线程的底层compareAndSwapInt方法
  • 原子类封装CAS
    • 内存偏移量valueOffset:通过反射获取字段在对象内存中的位置
    • CAS调用compareAndSet:直接操作内存地址实现原子更新
public class AtomicInteger {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset; // value 字段的内存偏移量

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

    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
}
  1. 循环CAS解决竞争
  • 自旋重试:若CAS失败,则循环尝试直到成功
public final int incrementAndGet() {
    int current;
    do {
        current = get(); // 读取当前值(volatile 保证最新值)
    } while (!compareAndSet(current, current + 1)); // CAS 更新
    return current + 1;
}

3.解决ABA问题

  • ABA问题:线程1读取值为A,之后值被其他线程修改为B又改回A,对于线程1而言仍然会成功,这里可能会导致逻辑错误。
  • 解决方案:AtomicStampedReference通过版本号(Stamp)标记值的变更
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
int stamp = ref.getStamp();
ref.compareAndSet(100, 101, stamp, stamp + 1); // 同时检查值和版本号

LongAdder 对比 AtomicLong

特性AtomicLongLonAdder
实现方式单一volatile变量+CAS分散Cell数组+CAS
高并发性能差(CAS竞争激烈时自旋次数过多)优(分散热点,减少竞争)
使用场景低并发计数高并发统计(如QPS计数器)
  • LongAdder原理:
    • 将值分散到多个cell中,线程竞争时优先更新各自Cell。
    • 最终结果通过合并所有Cell的值得到。

5.内存屏障与有序性

  • volatile写:插入StoreStore + StoreLoad屏障,确保写操作对其他线程可见。
  • volatile读:插入LoadLoad + LoadStore屏障,禁止重排序。

总结

Java原子类(如 AtomicInteger)通过 CAS 操作 和 volatile 变量 实现线程安全:

  1. volatile 保证值的可见性;
  2. Unsafe 类 调用底层 CAS 指令确保原子性;
  3. 循环 CAS 解决多线程竞争;
  4. 高并发场景下,LongAdder 通过分散热点优化性能;
  5. AtomicStampedReference 解决 ABA 问题。
    这种无锁设计在高并发下比 synchronized 更高效,但需注意自旋开销和 ABA 风险。”