JUC源码分析:深入探索Java并发编程的奥秘

一、引言
Java并发编程一直是Java开发者需要掌握的重要技能。在多线程编程中,JUC(java.util.concurrent)包提供了丰富的并发工具和类,帮助我们简化并发编程的复杂性。本文将深入分析JUC源码,帮助读者更好地理解Java并发编程的奥秘。
二、JUC简介
JUC是Java并发编程的核心库,它提供了以下几类工具和类:
1. 同步工具:如CountDownLatch、CyclicBarrier、Semaphore等;
2. 并发集合:如ConcurrentHashMap、CopyOnWriteArrayList等;
3. 线程池:如Executors、ThreadPoolExecutor等;
4. 并发框架:如FutureTask、Callable、CompletionService等。
三、源码分析
1. CountDownLatch
CountDownLatch是同步工具类,用于实现线程间的等待/通知模式。以下是其核心源码分析:
```java
public class CountDownLatch {
private final Sync sync;
private static final class Sync extends AbstractQueuedSynchronizer {
private final int count;
Sync(int count) {
this.count = count;
}
protected int tryAcquireShared(int acquires) {
return count == 0 ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
for (; count >= 0; count -= releases) {
return true;
}
throw new IllegalMonitorStateException();
}
}
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
public void await() throws InterruptedException {
sync.acquireShared(1);
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void countDown() {
sync.releaseShared(1);
}
}
```
CountDownLatch内部使用了一个Sync类,继承自AbstractQueuedSynchronizer(AQS)。Sync类维护了一个计数器count,表示剩余的等待线程数。await()方法使当前线程等待,直到count为0;countDown()方法使count减1。
2. ConcurrentHashMap
ConcurrentHashMap是JUC提供的并发集合之一,以下是其核心源码分析:
```java
public class ConcurrentHashMap
private static final int DEFAULT_CAPACITY = 16;
private static final float LOAD_FACTOR = 0.75f;
private static final int HASH_TABLE_SIZE = 1024;
transient volatile Set
transient volatile Set
transient volatile Set
transient volatile Node
private transient int size;
public ConcurrentHashMap() {
this(DEFAULT_CAPACITY, LOAD_FACTOR);
}
public ConcurrentHashMap(int initialCapacity) {
this(initialCapacity, LOAD_FACTOR);
}
public ConcurrentHashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0) throw new IllegalArgumentException("initialCapacity < 0");
if (initialCapacity > MAX_CAPACITY) initialCapacity = MAX_CAPACITY;
if (loadFactor <= 0f || Float.isNaN(loadFactor)) throw new IllegalArgumentException("loadFactor <= 0");
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity, loadFactor);
}
// ... 省略其他方法 ...
public V get(Object key) {
Node
return (e = getNode(key, hash(key))) == null ? null : e.value;
}
private Node
Node
if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[i = (n - 1) & hash]) != null) {
if (first.hash == hash && ((key == first.key) || (key != null && key.equals(first.key))))
return first;
for (e = first.next; e != null; e = e.next) {
if (e.hash == hash && ((key == e.key) || (key != null && key.equals(e.key))))
return e;
}
}
return null;
}
// ... 省略其他方法 ...
}
```
ConcurrentHashMap内部使用了一个Node数组作为存储结构,Node类实现了Map.Entry接口。在get()方法中,我们通过key的hash值定位到Node数组中的节点,然后遍历该节点及其后续节点,找到与key相匹配的节点,返回其value值。
3. ThreadPoolExecutor
ThreadPoolExecutor是JUC提供的线程池实现,以下是其核心源码分析:
```java
public class ThreadPoolExecutor extends AbstractExecutorService {
private final int corePoolSize;
private final int maximumPoolSize;
private final long keepAliveTime;
private final TimeUnit unit;
private final BlockingQueue
private final ThreadFactory threadFactory;
private final RejectedExecutionHandler handler;
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue
RejectedExecutionHandler handler) {
if (corePoolSize < 0 || maximumPoolSize <= 0 || corePoolSize > maximumPoolSize ||
keepAliveTime < 0) throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = keepAliveTime;
this.unit = unit;
this.workQueue = workQueue;
this.threadFactory = threadFactory;
this.handler = handler;
}
// ... 省略其他方法 ...
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = corePoolSize;
if (running && workQueue.offer(command)) {
int rs = resize();
if (rs >= 0 && c == corePoolSize)
c = rs;
}
if (c == corePoolSize && !workQueue.offer(command))
addThread(command);
}
private void addThread(Runnable command) {
synchronized (this) {
if (running && poolSize < maximumPoolSize) {
Thread t = threadFactory.newThread(command);
workers.add(t);
t.start();
}
}
}
// ... 省略其他方法 ...
}
```
ThreadPoolExecutor内部维护了一个BlockingQueue作为任务队列,以及一个Set作为工作线程集合。当任务到来时,首先检查核心线程池是否已满,如果未满,则创建新线程执行任务;如果已满,则将任务添加到任务队列。当核心线程池空闲时,会尝试从任务队列中获取任务执行。
四、总结
本文深入分析了JUC源码中的三个重要组件:CountDownLatch、ConcurrentHashMap和ThreadPoolExecutor。通过对这些源码的分析,我们可以更好地理解Java并发编程的原理,以及JUC如何帮助我们简化并发编程的复杂性。在今后的开发过程中,我们可以灵活运用JUC提供的并发工具和类,提高代码的执行效率和稳定性。




