JDK源码解析课,领悟Java编程思想的核心

40 阅读7分钟

微信图片_20251013140720_14_2.jpg

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. 动态扩容机制:采用1.5倍扩容策略,平衡内存使用和性能
  2. 快速失败机制:通过modCount实现并发修改检测
  3. 空间换时间:预留容量减少频繁扩容开销

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;
}

设计思想

  1. 哈希冲突解决:链表+红黑树(JDK8优化)
  2. 懒加载:首次插入时才初始化表
  3. 扩容优化:2倍扩容保持哈希均匀性
  4. 树化阈值:链表长度超过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;
        }
    }
}

设计思想

  1. AQS框架:基于AbstractQueuedSynchronizer实现同步器
  2. 可重入性:通过state计数支持同一线程多次获取锁
  3. 公平性选择:提供公平和非公平两种实现
  4. 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);
    }
}

设计思想

  1. 状态控制:使用ctl字段同时维护线程池状态和工作线程数
  2. 任务调度:核心线程->队列->非核心线程的调度策略
  3. 线程复用:通过Worker实现线程的循环利用
  4. 拒绝策略:提供多种拒绝策略处理饱和情况

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);
    }
    
    // 其他方法...
}

设计思想

  1. 装饰器模式:继承InputStream提供统一接口
  2. 本地方法:实际IO操作通过JNI调用本地代码实现
  3. 资源管理:通过FileDescriptor管理文件资源
  4. 安全检查:通过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;
    }
}

设计思想

  1. 多路复用:单线程管理多个通道
  2. 事件驱动:基于就绪选择而非阻塞等待
  3. 平台适配:不同操作系统有不同实现
  4. 高效唤醒:使用管道实现选择器唤醒

4. 总结与编程思维提炼

通过JDK源码分析,我们可以提炼出以下核心编程思想:

  1. 接口与实现分离:如Collection与ArrayList/HashSet的关系
  2. 设计模式应用
    • 迭代器模式(集合遍历)
    • 装饰器模式(IO流)
    • 模板方法模式(AQS)
  3. 并发控制策略
    • CAS乐观锁(Atomic类)
    • AQS同步框架(ReentrantLock)
    • 读写分离(CopyOnWriteArrayList)
  4. 性能优化技巧
    • 懒加载(HashMap.table)
    • 空间换时间(缓存设计)
    • 减少锁粒度(ConcurrentHashMap分段锁)

进阶学习建议

  1. 深入理解JVM内存模型与GC机制
  2. 研究Java模块化系统(JPMS)
  3. 分析Java新特性实现(如var、record等)
  4. 探索JVM性能调优技术

通过源码学习,不仅能掌握Java底层原理,更能培养出优秀的编程思维和架构设计能力。建议读者选择自己感兴趣的核心类,按照"使用场景->API设计->实现细节->性能考量"的思路进行系统分析。