JDK源码解析课,领悟Java编程思想的核心---youkeit.xyz/2183/
面向学习者的 JDK 源码解析:从源码到思想,系统领悟 Java 核心编程思维
1. Java 集合框架解析
1.1 ArrayList 核心实现解析
ArrayList 是 Java 中最常用的动态数组实现,让我们深入分析其核心源码:
// ArrayList 的核心字段
transient Object[] elementData; // 实际存储元素的数组
private int size; // 当前元素数量
private static final int DEFAULT_CAPACITY = 10; // 默认初始容量
// 关键方法:add(E e)
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确保容量足够
elementData[size++] = e; // 添加元素到数组末尾
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // 修改计数器,用于快速失败机制
// 如果所需容量超过当前数组长度,则扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量 = 旧容量 * 1.5
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity); // 复制到新数组
}
设计思想:
- 动态扩容机制:采用1.5倍扩容策略,平衡内存使用和性能
- 快速失败机制:通过modCount实现并发修改检测
- 空间换时间:预留容量减少频繁扩容开销
1.2 HashMap 源码深度解析
HashMap 是 Java 集合框架中最复杂的类之一,理解其实现对掌握 Java 编程思想至关重要。
// HashMap 核心字段
transient Node<K,V>[] table; // 哈希桶数组
transient int size; // 键值对数量
int threshold; // 扩容阈值
final float loadFactor; // 负载因子(默认0.75)
// 哈希节点定义
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
// 构造方法和其他实现...
}
// 关键方法:putVal
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
// 第一次插入时初始化table
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// 计算桶位置,如果为空则直接插入
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
// 检查第一个节点是否匹配
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 如果是树节点
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
// 遍历链表
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// 更新现有键的值
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
设计思想:
- 哈希冲突解决:链表+红黑树(JDK8优化)
- 懒加载:首次插入时才初始化表
- 扩容优化:2倍扩容保持哈希均匀性
- 树化阈值:链表长度超过8转为红黑树,提高查询效率
2. 并发编程模型解析
2.1 ReentrantLock 实现原理
// ReentrantLock 核心实现
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
// 实现AQS的抽象方法
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
}
// 非公平锁实现
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
// 公平锁实现
static final class FairSync extends Sync {
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
}
设计思想:
- AQS框架:基于AbstractQueuedSynchronizer实现同步器
- 可重入性:通过state计数支持同一线程多次获取锁
- 公平性选择:提供公平和非公平两种实现
- CAS操作:使用compareAndSetState保证原子性
2.2 ThreadPoolExecutor 工作原理解析
// ThreadPoolExecutor 核心字段
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private final BlockingQueue<Runnable> workQueue;
private final HashSet<Worker> workers = new HashSet<Worker>();
private volatile ThreadFactory threadFactory;
private volatile RejectedExecutionHandler handler;
// Worker内部类
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
final Thread thread;
Runnable firstTask;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
// 省略其他方法...
}
// 关键方法:execute
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 当前工作线程数小于核心线程数
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 尝试加入工作队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 尝试创建非核心线程
else if (!addWorker(command, false))
reject(command);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
try {
task.run();
afterExecute(task, null);
} catch (Throwable ex) {
afterExecute(task, ex);
throw ex;
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
设计思想:
- 状态控制:使用ctl字段同时维护线程池状态和工作线程数
- 任务调度:核心线程->队列->非核心线程的调度策略
- 线程复用:通过Worker实现线程的循环利用
- 拒绝策略:提供多种拒绝策略处理饱和情况
3. Java IO/NIO 模型解析
3.1 FileInputStream 实现原理
public class FileInputStream extends InputStream {
private final FileDescriptor fd;
private final String path;
private volatile boolean closed = false;
// 本地方法声明
private native void open0(String name) throws FileNotFoundException;
private native int read0() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
fd = new FileDescriptor();
fd.attach(this);
path = name;
open0(name);
}
public int read() throws IOException {
return read0();
}
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
// 其他方法...
}
设计思想:
- 装饰器模式:继承InputStream提供统一接口
- 本地方法:实际IO操作通过JNI调用本地代码实现
- 资源管理:通过FileDescriptor管理文件资源
- 安全检查:通过SecurityManager实现访问控制
3.2 Selector 多路复用实现
public abstract class Selector implements Closeable {
protected Selector() { }
public static Selector open() throws IOException {
return SelectorProvider.provider().openSelector();
}
public abstract Set<SelectionKey> keys();
public abstract Set<SelectionKey> selectedKeys();
public abstract int selectNow() throws IOException;
public abstract int select(long timeout) throws IOException;
public abstract int select() throws IOException;
public abstract Selector wakeup();
public abstract void close() throws IOException;
}
// Selector实现类(WindowsSelectorImpl)
class WindowsSelectorImpl extends SelectorImpl {
// 管道用于唤醒
private final Pipe wakeupPipe;
private final int wakeupSourceFd;
private final int wakeupSinkFd;
// 本地方法声明
private native int poll0(long pollAddress, int numfds, int[] readFds,
int[] writeFds, int[] exceptFds, long timeout);
protected int doSelect(long timeout) throws IOException {
if (channelArray == null)
throw new ClosedSelectorException();
processDeregisterQueue();
if (interruptTriggered) {
resetWakeupSocket();
return 0;
}
// 计算要poll的文件描述符数量
int numKeysUpdated = 0;
try {
begin();
// 调用本地方法进行poll
numKeysUpdated = poll0(pollArrayAddress,
totalChannels,
readFds, writeFds, exceptFds, timeout);
} finally {
end();
}
processDeregisterQueue();
if (numKeysUpdated > 0) {
numKeysUpdated = 0;
for (int i = 0; i < totalChannels; i++) {
int rOps = pollArray.getEventOps(i);
if (rOps != 0) {
SelectionKeyImpl ski = channelArray[i];
if (ski != null) {
if (selectedKeys.contains(ski)) {
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
numKeysUpdated++;
}
} else {
ski.channel.translateAndSetReadyOps(rOps, ski);
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
selectedKeys.add(ski);
numKeysUpdated++;
}
}
}
}
}
}
return numKeysUpdated;
}
}
设计思想:
- 多路复用:单线程管理多个通道
- 事件驱动:基于就绪选择而非阻塞等待
- 平台适配:不同操作系统有不同实现
- 高效唤醒:使用管道实现选择器唤醒
4. 总结与编程思维提炼
通过JDK源码分析,我们可以提炼出以下核心编程思想:
- 接口与实现分离:如Collection与ArrayList/HashSet的关系
- 设计模式应用:
- 迭代器模式(集合遍历)
- 装饰器模式(IO流)
- 模板方法模式(AQS)
- 并发控制策略:
- CAS乐观锁(Atomic类)
- AQS同步框架(ReentrantLock)
- 读写分离(CopyOnWriteArrayList)
- 性能优化技巧:
- 懒加载(HashMap.table)
- 空间换时间(缓存设计)
- 减少锁粒度(ConcurrentHashMap分段锁)
进阶学习建议:
- 深入理解JVM内存模型与GC机制
- 研究Java模块化系统(JPMS)
- 分析Java新特性实现(如var、record等)
- 探索JVM性能调优技术
通过源码学习,不仅能掌握Java底层原理,更能培养出优秀的编程思维和架构设计能力。建议读者选择自己感兴趣的核心类,按照"使用场景->API设计->实现细节->性能考量"的思路进行系统分析。