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