JUC 并发工具与线程安全源码深度解析

JUC 并发工具与线程安全源码深度解析

一、CountDownLatch 源码

1.1 原理

基于 AQS 的共享模式实现,允许一个或多个线程等待其他线程完成。

1.2 源码

java 复制代码
public class CountDownLatch {
    
    // 内部类,继承 AQS 的共享模式
    private static final class Sync extends AbstractQueuedSynchronizer {
        
        Sync(int count) {
            setState(count);  // state = 计数器值
        }
        
        int getCount() {
            return getState();
        }
        
        // 共享模式尝试获取锁
        protected int tryAcquireShared(int acquires) {
            // state == 0 时返回 1(获取成功),否则返回 -1(获取失败)
            return (getState() == 0) ? 1 : -1;
        }
        
        // 共享模式尝试释放锁
        protected boolean tryReleaseShared(int releases) {
            // 递减 state
            for (;;) {
                int c = getState();
                if (c == 0) return false;  // 已经到 0,不再递减
                int nextc = c - 1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;  // 到 0 时唤醒所有等待线程
            }
        }
    }
    
    private final Sync sync;
    
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException();
        this.sync = new Sync(count);
    }
    
    // 等待(阻塞直到计数器为 0)
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    // 等待(带超时)
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }
    
    // 计数器减 1
    public void countDown() {
        sync.releaseShared(1);
    }
    
    // 获取当前计数
    public long getCount() {
        return sync.getCount();
    }
}

1.3 使用场景

java 复制代码
// 场景:主线程等待多个子任务完成
public class CountDownLatchDemo {
    
    public void mainTask() throws InterruptedException {
        int taskCount = 5;
        CountDownLatch latch = new CountDownLatch(taskCount);
        ExecutorService executor = Executors.newFixedThreadPool(5);
        
        for (int i = 0; i < taskCount; i++) {
            executor.submit(() -> {
                try {
                    // 子任务处理
                    doSubTask();
                } finally {
                    latch.countDown();  // 完成一个,计数器 -1
                }
            });
        }
        
        latch.await();  // 主线程等待所有子任务完成
        System.out.println("所有子任务完成");
        executor.shutdown();
    }
}

二、CyclicBarrier 源码

2.1 原理

基于 ReentrantLock + Condition 实现,支持重复使用。

2.2 源码

java 复制代码
public class CyclicBarrier {
    
    private static class Generation {
        boolean broken = false;
    }
    
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition trip = lock.newCondition();
    
    private final int parties;           // 参与方数量
    private int count;                   // 当前等待数量
    private final Runnable barrierCommand;  // 屏障动作
    private Generation generation = new Generation();
    
    public CyclicBarrier(int parties, Runnable barrierAction) {
        this.parties = parties;
        this.count = parties;
        this.barrier_command = barrierAction;
    }
    
    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe);
        }
    }
    
    private int dowait(boolean timed, long nanos) throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lock();  // 加锁
        
        try {
            final Generation g = generation;
            
            if (g.broken) throw new BrokenBarrierException();
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }
            
            int index = --count;  // 递减计数
            
            if (index == 0) {
                // 最后一个到达的线程
                boolean tripped = false;
                try {
                    // 执行屏障动作
                    if (barrierCommand != null)
                        barrierCommand.run();
                    tripped = true;
                } finally {
                    if (!tripped) breakBarrier();
                }
                
                // 唤醒所有等待线程
                trip.signalAll();
                // 重置计数器(下一代)
                nextGeneration();
                return 0;
            }
            
            // 不是最后一个,等待
            for (;;) {
                try {
                    if (!timed)
                        trip.await();  // 等待
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    if (g == generation && !g.broken) {
                        breakBarrier();
                        throw ie;
                    }
                }
                
                if (g.broken) throw new BrokenBarrierException();
                if (g != generation) return index;  // 新一代,返回
            }
        } finally {
            lock.unlock();
        }
    }
    
    // 重置
    public void reset() {
        lock.lock();
        try {
            breakBarrier();
            nextGeneration();
        } finally {
            lock.unlock();
        }
    }
    
    private void nextGeneration() {
        trip.signalAll();
        count = parties;  // 重置计数
        generation = new Generation();  // 新一代
    }
}

2.3 CountDownLatch vs CyclicBarrier

维度 CountDownLatch CyclicBarrier
计数器 一次性 可重复使用
等待 一个或多个线程等待其他线程 N 个线程互相等待
屏障动作 支持 barrierAction
实现 AQS 共享模式 ReentrantLock + Condition

三、Semaphore 源码

3.1 原理

基于 AQS 的共享模式,控制同时访问的线程数。

3.2 源码

java 复制代码
public class Semaphore {
    
    private final Sync sync;
    
    abstract static class Sync extends AbstractQueuedSynchronizer {
        Sync(int permits) {
            setState(permits);  // state = 许可数
        }
        
        // 非公平模式
        static final class NonfairSync extends Sync {
            protected int tryAcquireShared(int acquires) {
                return nonfairTryAcquireShared(acquires);
            }
            
            final int nonfairTryAcquireShared(int acquires) {
                for (;;) {
                    int available = getState();
                    int remaining = available - acquires;
                    if (remaining < 0 || compareAndSetState(available, remaining))
                        return remaining;
                }
            }
        }
        
        // 公平模式
        static final class FairSync extends Sync {
            protected int tryAcquireShared(int acquires) {
                for (;;) {
                    // 公平模式:检查是否有前驱节点
                    if (hasQueuedPredecessors()) return -1;
                    
                    int available = getState();
                    int remaining = available - acquires;
                    if (remaining < 0 || compareAndSetState(available, remaining))
                        return remaining;
                }
            }
        }
    }
    
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }
    
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
    
    // 获取许可(阻塞)
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    // 获取许可(带超时)
    public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }
    
    // 释放许可
    public void release() {
        sync.releaseShared(1);
    }
}

3.3 使用场景

java 复制代码
// 限流:控制同时访问的线程数
public class SemaphoreDemo {
    
    private Semaphore semaphore = new Semaphore(3);  // 最多 3 个并发
    
    public void access() throws InterruptedException {
        semaphore.acquire();  // 获取许可
        try {
            // 访问资源
            doSomething();
        } finally {
            semaphore.release();  // 释放许可
        }
    }
}

四、BlockingQueue 源码

4.1 ArrayBlockingQueue

java 复制代码
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E> {
    
    final Object[] items;    // 底层数组
    int takeIndex;           // 出队位置
    int putIndex;            // 入队位置
    int count;               // 元素个数
    
    final ReentrantLock lock;
    private final Condition notEmpty;  // 非空条件
    private final Condition notFull;   // 非满条件
    
    public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull = lock.newCondition();
    }
    
    // 入队(阻塞)
    public void put(E e) throws InterruptedException {
        Objects.requireNonNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            // 队列满了,等待
            while (count == items.length)
                notFull.await();
            
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
    
    // 出队(阻塞)
    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            // 队列空了,等待
            while (count == 0)
                notEmpty.await();
            
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
    
    private void enqueue(E x) {
        items[putIndex] = x;
        if (++putIndex == items.length) putIndex = 0;  // 循环数组
        count++;
        notEmpty.signal();  // 唤醒等待出队的线程
    }
    
    private E dequeue() {
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;  // help GC
        if (++takeIndex == items.length) takeIndex = 0;
        count--;
        notFull.signal();  // 唤醒等待入队的线程
        return x;
    }
}

4.2 LinkedBlockingQueue

java 复制代码
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E> {
    
    static class Node<E> {
        E item;
        Node<E> next;
        Node(E x) { item = x; }
    }
    
    private final int capacity;
    transient Node<E> head;      // 链表头
    private transient Node<E> last;  // 链表尾
    
    private final ReentrantLock takeLock = new ReentrantLock();
    private final Condition notEmpty = takeLock.newCondition();
    
    private final ReentrantLock putLock = new ReentrantLock();
    private final Condition notFull = putLock.newCondition();
    
    int count;
    
    // 入队
    public void put(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        
        final ReentrantLock putLock = this.putLock;
        final AtomicInteger count = this.count;
        putLock.lockInterruptibly();
        try {
            while (count.get() == capacity)
                notFull.await();
            
            enqueue(e);
            
            int c = count.getAndIncrement();
            if (c + 1 < capacity)
                notFull.signal();
        } finally {
            putLock.unlock();
        }
        
        if (c == 0)
            signalNotEmpty();
    }
    
    // 出队
    public E take() throws InterruptedException {
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0)
                notEmpty.await();
            
            E x = dequeue();
            
            int c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        
        signalNotFull();
        return x;
    }
}

4.3 各种 BlockingQueue 对比

队列 底层结构 有界
ArrayBlockingQueue 数组 有界 一把锁
LinkedBlockingQueue 链表 可选 两把锁(takeLock/putLock)
PriorityBlockingQueue 无界 一把锁
DelayQueue 无界 一把锁
SynchronousQueue 无存储 CAS/锁

五、ThreadLocal 源码

5.1 核心结构

java 复制代码
public class ThreadLocal<T> {
    
    // 每个 Thread 持有一个 ThreadLocalMap
    // ThreadLocal 对象作为 key
    
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T) e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;  // Thread 的成员变量
    }
    
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
}

5.2 ThreadLocalMap 源码

java 复制代码
static class ThreadLocalMap {
    
    // Entry 继承 WeakReference,key 是弱引用
    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    
    private static final int INITIAL_CAPACITY = 16;
    private Entry[] table;
    private int size = 0;
    private int threshold;
    
    ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
        table = new Entry[INITIAL_CAPACITY];
        int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
        table[i] = new Entry(firstKey, firstValue);
        size = 1;
        setThreshold(INITIAL_CAPACITY);
    }
    
    private void set(ThreadLocal<?> key, Object value) {
        Entry[] tab = table;
        int len = tab.length;
        int i = key.threadLocalHashCode & (len - 1);
        
        // 线性探测法解决哈希冲突
        for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
            ThreadLocal<?> k = e.get();
            
            if (k == key) {
                e.value = value;
                return;
            }
            
            if (k == null) {
                // key 已被 GC 回收(内存泄漏的入口)
                replaceStaleEntry(key, value, e);
                return;
            }
        }
        
        tab[i] = new Entry(key, value);
        if (++size >= threshold)
            rehash();
    }
}

5.3 内存泄漏问题

csharp 复制代码
ThreadLocalMap 的 key 是弱引用:
├── ThreadLocal 对象被 GC 回收后,key 变为 null
├── 但 Entry 的 value 还被 ThreadLocalMap 强引用
├── 如果 Thread 一直存活(线程池),value 永远不会被回收
└── 这就是内存泄漏

解决方案:
├── 使用完调用 remove()
├── InheritableThreadLocal(父子线程传递)
└── TransmittableThreadLocal(线程池场景)

5.4 最佳实践

java 复制代码
// 正确用法
public class UserContext {
    
    private static final ThreadLocal<Long> USER_ID = new ThreadLocal<>();
    
    public static void setUserId(Long userId) {
        USER_ID.set(userId);
    }
    
    public static Long getUserId() {
        return USER_ID.get();
    }
    
    // 必须清理!
    public static void clear() {
        USER_ID.remove();
    }
}

// 在 Filter/Interceptor 中设置和清理
public class AuthInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, ...) {
        Long userId = parseUserId(request);
        UserContext.setUserId(userId);
        return true;
    }
    
    @Override
    public void afterCompletion(...) {
        UserContext.clear();  // 必须清理!
    }
}

六、Atomic 原子类源码

6.1 AtomicInteger

java 复制代码
public class AtomicInteger extends Number implements java.io.Serializable {
    
    // 使用 Unsafe 直接操作内存
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    
    static {
        try {
            valueOffset = unsafe.objectFieldOffset(
                AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    
    private volatile int value;
    
    // CAS 操作
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    
    // 原子递增
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    
    // 原子递减
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }
}

6.2 LongAdder(高并发计数器)

java 复制代码
// LongAdder 比 AtomicLong 在高并发下性能更好
// 原理:分散热点,减少 CAS 冲突
public class LongAdder extends Striped64 {
    
    // 多个 Cell 分散热点
    transient volatile Cell[] cells;
    
    // 基础值
    transient volatile long base;
    
    // 锁(只在扩容时使用)
    transient volatile int cellsBusy;
    
    public void increment() {
        add(1L);
    }
    
    public void add(long x) {
        Cell[] as; long b, v; int m; Cell a;
        
        if ((as = cells) != null || !casBase(b = base, b + x)) {
            boolean uncontended = true;
            
            if (as == null || (m = as.length - 1) < 0 ||
                (a = as[getProbe() & m]) == null ||
                !(uncontended = a.cas(v = a.value, v + x)))
                longAccumulate(x, null, uncontended);
        }
    }
    
    // 获取总和
    public long sum() {
        Cell[] as = cells; Cell a;
        long sum = base;
        if (as != null) {
            for (int i = 0; i < as.length; ++i) {
                if ((a = as[i]) != null)
                    sum += a.value;
            }
        }
        return sum;
    }
}

七、面试题精选

Q1:CountDownLatch 和 CyclicBarrier 的区别?

CountDownLatch 一次性,一个或多个线程等待其他线程;CyclicBarrier 可重复,N 个线程互相等待。


Q2:Semaphore 的原理?

基于 AQS 共享模式,state 表示许可数,acquire 递减,release 递增。


Q3:ArrayBlockingQueue 和 LinkedBlockingQueue 的区别?

ArrayBlockingQueue 有界、一把锁;LinkedBlockingQueue 可选有界、两把锁(读写分离)。


Q4:ThreadLocal 的内存泄漏问题?

key 是弱引用,被 GC 后 value 仍被强引用,线程池场景下永不回收。解决:用完 remove()。


Q5:ThreadLocalMap 如何解决哈希冲突?

线性探测法,找到空位或相同 key 的位置。


Q6:LongAdder 为什么比 AtomicLong 快?

分散热点,多个 Cell 减少 CAS 冲突,sum 时汇总。


Q7:AtomicInteger 的 CAS 原理?

Unsafe.compareAndSwapInt,直接操作内存,volatile 保证可见性。


Q8:ConcurrentHashMap 的 size 如何保证准确?

baseCount + counterCells 数组求和,类似 LongAdder 思路。


Q9:CopyOnWriteArrayList 的原理?

写时复制,写操作加锁并复制新数组,读操作无锁。适合读多写少。


Q10:线程池的核心参数?

corePoolSize、maximumPoolSize、keepAliveTime、workQueue、threadFactory、handler

相关推荐
只爱喝胡辣汤1 小时前
03-KafkaProducer 源码分析
后端
只爱喝胡辣汤1 小时前
13-KRaft 元数据管理与 Raft 协议源码分析
后端
只爱喝胡辣汤1 小时前
异步线程深度剖析(CompletableFuture/异步模式/虚拟线程)
后端
苏三说技术1 小时前
推荐一个比ES快5倍的搜索引擎
后端
二月龙1 小时前
Java 线程池核心参数详解:从原理到生产避坑
后端
小强19881 小时前
线上 Java 项目 CPU 飙升、OOM 排查思路:完整实战流程
后端
学编程就要猛1 小时前
流式编程及Spring中SSE实现
java·后端·spring·流式编程
wechatbot8881 小时前
SpringBoot Vue 企业微信多账号托管|扫码登录 代理 IP 消息回调
大数据·后端·微信·企业微信·ai编程
不才不才不不才2 小时前
Spring 源码系列(27): @Transactional 七大失效场景与源码归因
java·后端·spring