深入解析进程与线程:并发编程基础与实践
1. 进程与线程的本质解析在计算机科学领域理解进程和线程的概念是掌握并发编程的基础。让我们从一个实际场景开始当你同时打开浏览器、音乐播放器和文档编辑器时操作系统会为每个应用程序创建独立的进程。这种设计确保了即使某个程序崩溃比如浏览器突然关闭其他程序如正在播放的音乐仍能继续运行不受影响。1.1 进程的深入剖析进程是操作系统进行资源分配的基本单位它本质上是一个正在执行的程序实例。想象一家现代化餐厅的运营独立厨房内存空间每个进程都拥有自己独立的内存区域包括代码段、数据段和堆栈段。就像不同餐厅的厨房完全隔离一个餐厅的食材不会莫名其妙跑到另一家餐厅去。专属厨具系统资源操作系统为每个进程分配文件描述符、网络端口等资源类似每家餐厅都有自己的厨具和设备清单。卫生隔离安全性进程间的隔离机制确保了安全性。即使某个进程被恶意软件感染也不会直接影响其他进程就像餐厅之间的防疫措施。关键特性创建进程fork通常需要复制父进程的地址空间在Linux系统中通过写时复制Copy-On-Write技术优化进程间通信IPC需要特殊机制管道、消息队列、共享内存等上下文切换开销较大需要保存/恢复完整的进程状态通常需要几千个时钟周期1.2 线程的运作机制线程是进程内的执行单元可以理解为餐厅里的工作人员。继续我们的餐厅类比共享资源所有线程共享进程的全局变量和堆内存就像餐厅员工共用厨房设备和食材仓库。独立工作流每个线程有自己的程序计数器PC和栈空间记录执行位置和局部变量如同每位员工有自己的工作任务清单。高效协作线程间通信可以直接通过共享内存进行比进程间通信快10-100倍就像餐厅员工之间口头沟通比打电话给其他餐厅快得多。重要特点线程上下文切换只需保存寄存器状态和栈指针通常几百个时钟周期线程创建和销毁的开销比进程小一个数量级缺乏保护机制一个线程的错误可能破坏整个进程的地址空间1.3 进程与线程的对比分析通过下表我们可以清晰看到两者的核心差异对比维度进程线程资源占用独立内存空间通常MB级共享进程内存只需KB级栈空间创建开销需要建立完整的地址空间较慢只需建立执行上下文较快通信方式必须使用IPC机制速度较慢可直接访问共享内存速度极快容错性一个进程崩溃不影响其他进程一个线程崩溃可能导致整个进程终止适用场景需要高隔离性的任务需要高效协作的任务在实际开发中选择进程还是线程需要考虑以下因素安全性要求高的场景如支付系统倾向使用进程隔离性能敏感型应用如游戏服务器通常采用多线程线程池现代趋势是混合使用如Chrome浏览器每个标签页是独立进程页面渲染使用多线程2. 多线程编程的核心价值2.1 性能提升的实际表现多线程最直观的优势是提高系统吞吐量。假设我们有一个图像处理程序需要处理100张图片// 单线程版本 long start System.currentTimeMillis(); for (int i 0; i 100; i) { processImage(i); // 每张图片处理耗时200ms } long duration System.currentTimeMillis() - start; // 总耗时约20000ms (20秒) // 多线程版本4核CPU ExecutorService executor Executors.newFixedThreadPool(4); start System.currentTimeMillis(); for (int i 0; i 100; i) { final int index i; executor.submit(() - processImage(index)); } executor.shutdown(); executor.awaitTermination(1, TimeUnit.HOURS); duration System.currentTimeMillis() - start; // 总耗时约5000ms (5秒)这个例子展示了理想情况下无资源竞争的线性加速比。但实际开发中需要注意线程数不是越多越好通常推荐CPU核心数×1等待时间/计算时间I/O密集型应用可以从更多线程中受益计算密集型应用线程数不应超过CPU核心数2.2 响应性提升的典型场景图形界面程序是最能体现多线程价值的场景之一。假设我们开发一个文件下载器// 错误实现在主线程执行下载 downloadButton.setOnAction(event - { downloadFile(url); // 可能耗时几分钟 updateProgressBar(100); // 界面冻结无法更新 }); // 正确实现使用后台线程 downloadButton.setOnAction(event - { new Thread(() - { downloadFile(url); Platform.runLater(() - updateProgressBar(100)); }).start(); });关键经验Android和JavaFX等UI框架都有主线程UI线程限制耗时超过100ms的操作都应放在后台线程更新UI必须回到主线程Platform.runLater/SwingUtilities.invokeLater2.3 设计模式的简化多线程可以自然实现生产者-消费者模式BlockingQueueItem queue new LinkedBlockingQueue(100); // 生产者线程 new Thread(() - { while (true) { Item item produceItem(); queue.put(item); // 队列满时自动阻塞 } }).start(); // 消费者线程 new Thread(() - { while (true) { Item item queue.take(); // 队列空时自动阻塞 consumeItem(item); } }).start();这种设计解耦了生产与消费逻辑通过队列自动实现流量控制可以轻松扩展多生产者/多消费者3. Java线程实现详解3.1 线程创建的五种方式对比方式1继承Thread类class MyThread extends Thread { Override public void run() { // 线程执行逻辑 } } // 使用 new MyThread().start();适用场景简单demo或测试代码缺点Java单继承限制不符合面向接口编程原则方式2实现Runnable接口class MyRunnable implements Runnable { Override public void run() { // 线程执行逻辑 } } // 使用 new Thread(new MyRunnable()).start();优势避免继承限制任务与执行器分离方便使用线程池方式3FutureTask CallableCallableInteger task () - { // 返回计算结果 return 42; }; FutureTaskInteger futureTask new FutureTask(task); new Thread(futureTask).start(); // 获取结果阻塞 Integer result futureTask.get();特点可以获取返回值可以捕获异常配合线程池使用更高效方式4线程池提交ExecutorService executor Executors.newCachedThreadPool(); FutureInteger future executor.submit(() - { // 计算并返回结果 return calculateResult(); }); // 其他操作... Integer result future.get(); // 需要时获取最佳实践生产环境推荐使用线程池避免频繁创建销毁线程可以控制并发数量方式5CompletableFuture (Java8)CompletableFuture.supplyAsync(() - fetchData()) .thenApply(data - processData(data)) .thenAccept(result - showResult(result));现代特性链式异步编程异常处理机制组合多个异步任务3.2 线程方法的深度解析start() vs run() 的底层差异Thread thread new Thread(() - System.out.println(Running...)); // 错误用法直接调用run() thread.run(); // 同步执行在调用者线程运行 // 正确用法启动线程 thread.start(); // 异步执行JVM调用native方法创建系统线程底层机制start()调用本地方法start0()JVM请求操作系统创建新线程线程准备就绪后回调run()方法线程终止后释放资源sleep() 的精细控制// 传统sleep Thread.sleep(100); // 毫秒 // Java14更精确的sleep Thread.sleep(Duration.ofMillis(100)); // 注意事项 // 1. 会抛出InterruptedException // 2. 不释放锁 // 3. 实际睡眠时间可能比指定长系统调度join() 的同步妙用Thread t1 new Thread(task1); Thread t2 new Thread(task2); t1.start(); t2.start(); // 等待两个线程完成 t1.join(); // 当前线程阻塞直到t1结束 t2.join(); // 当前线程阻塞直到t2结束 // 带超时的join t1.join(500); // 最多等待500ms使用场景主线程等待子线程完成线程间顺序执行控制资源初始化等待4. 线程状态机与生命周期4.1 状态转换全景图Java线程的生命周期包含6种状态其转换关系如下图所示[NEW] → [RUNNABLE] ↔ [BLOCKED] ↓ [WAITING] ↑ [TIMED_WAITING] ↓ [TERMINATED]4.2 状态转换触发条件NEW → RUNNABLE调用start()方法后立即进入RUNNABLE注意不是立即运行等待OS调度RUNNABLE ↔ BLOCKED进入BLOCKED尝试获取synchronized锁失败返回RUNNABLE成功获取锁RUNNABLE → WAITING调用Object.wait()调用Thread.join()调用LockSupport.park()WAITING → RUNNABLEObject.notify()/notifyAll()LockSupport.unpark()被join的线程终止RUNNABLE → TIMED_WAITINGThread.sleep(long)Object.wait(long)Thread.join(long)LockSupport.parkNanos()/parkUntil()RUNNABLE → TERMINATEDrun()方法正常结束抛出未捕获异常4.3 状态监测实战Thread thread new Thread(() - { try { synchronized (lock) { lock.wait(1000); } } catch (InterruptedException e) { e.printStackTrace(); } }); // 监控线程状态 new Thread(() - { while (true) { System.out.println(thread.getState()); try { Thread.sleep(200); } catch (InterruptedException e) { break; } } }).start(); thread.start();典型输出顺序NEWRUNNABLE (after start)BLOCKED (trying to acquire lock)TIMED_WAITING (after wait)RUNNABLE (after notify/timeout)TERMINATED5. 线程安全与同步机制5.1 竞态条件实例分析class Counter { private int count 0; public void increment() { count; // 非原子操作 } }这个简单的自增操作实际上包含三个步骤读取count值到寄存器寄存器值加1写回count变量在多线程环境下可能出现线程A读取count为0线程B也读取count为0都加1后写回结果count是1而不是25.2 synchronized关键字详解// 实例方法同步 public synchronized void increment() { count; } // 等价于 public void increment() { synchronized(this) { count; } } // 静态方法同步 public static synchronized void staticMethod() { // 锁的是Class对象 } // 同步代码块 public void method() { // 非同步代码 synchronized(lockObject) { // 临界区 } }锁特性可重入同一线程可重复获取已持有的锁独占性一次只有一个线程能持有锁互斥性其他线程必须等待锁释放5.3 volatile的内存语义class Shared { private volatile boolean flag false; public void setFlag() { flag true; // 写操作具有原子性和可见性 } public boolean checkFlag() { return flag; // 读操作总能获取最新值 } }volatile保证可见性写操作立即对其他线程可见禁止指令重排序不保证复合操作的原子性适用场景状态标志位一次性安全发布独立观察如统计计数器5.4 原子类实战AtomicInteger counter new AtomicInteger(0); // 线程安全的自增 counter.incrementAndGet(); // CAS操作 int oldValue, newValue; do { oldValue counter.get(); newValue calculateNewValue(oldValue); } while (!counter.compareAndSet(oldValue, newValue));原子类优势比锁更轻量级适合简单原子操作内置常见运算方法实现原理基于CPU的CAS指令自旋重试机制volatile变量保证可见性6. 线程池最佳实践6.1 核心参数解析ThreadPoolExecutor executor new ThreadPoolExecutor( 5, // 核心线程数 10, // 最大线程数 60, // 空闲线程存活时间(秒) TimeUnit.SECONDS, new ArrayBlockingQueue(100), // 工作队列 Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() // 拒绝策略 );参数配置原则CPU密集型核心数 ≈ CPU核心数I/O密集型核心数 ≈ CPU核心数 × (1 平均等待时间/平均计算时间)队列容量根据业务特点设置通常100-10000拒绝策略根据业务容忍度选择6.2 四种预定义线程池// 1. 固定大小线程池 Executors.newFixedThreadPool(10); // 2. 可缓存线程池 Executors.newCachedThreadPool(); // 3. 单线程池 Executors.newSingleThreadExecutor(); // 4. 定时任务线程池 Executors.newScheduledThreadPool(5);使用建议生产环境建议自定义ThreadPoolExecutornewCachedThreadPool慎用可能创建过多线程定时任务优先使用ScheduledThreadPoolExecutor6.3 线程池监控技巧ThreadPoolExecutor executor (ThreadPoolExecutor) Executors.newFixedThreadPool(5); // 定期监控 new Timer().scheduleAtFixedRate(() - { System.out.println(活跃线程数: executor.getActiveCount()); System.out.println(已完成任务数: executor.getCompletedTaskCount()); System.out.println(队列大小: executor.getQueue().size()); }, 0, 1000);扩展方案继承ThreadPoolExecutor重写before/afterExecute实现RejectedExecutionHandler记录被拒任务使用Micrometer等监控库集成到监控系统7. 并发编程常见陷阱7.1 死锁的四个必要条件互斥条件资源一次只能被一个线程占用占有且等待线程持有资源并等待其他资源不可抢占资源只能由持有者释放循环等待存在线程循环等待资源链// 典型死锁代码 Object lock1 new Object(); Object lock2 new Object(); new Thread(() - { synchronized(lock1) { Thread.sleep(100); synchronized(lock2) { // ... } } }).start(); new Thread(() - { synchronized(lock2) { Thread.sleep(100); synchronized(lock1) { // ... } } }).start();解决方案锁排序按固定顺序获取锁锁超时tryLock设置超时时间死锁检测定期检查线程依赖图7.2 线程泄漏的预防线程泄漏常见场景忘记关闭线程池任务无限期阻塞线程创建无上限// 正确关闭线程池 ExecutorService executor Executors.newFixedThreadPool(5); try { // 提交任务... } finally { executor.shutdown(); // 温和关闭 if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); // 强制关闭 } }防御措施使用try-with-resources管理ExecutorService为任务设置超时机制监控线程数量异常增长7.3 上下文切换开销测量上下文切换开销的方法long start System.nanoTime(); for (int i 0; i 1000000; i) { Thread.yield(); // 主动让出CPU } long duration System.nanoTime() - start; System.out.println(平均上下文切换时间: duration/1000000 ns);优化建议避免创建过多线程减小锁粒度使用线程本地存储(ThreadLocal)考虑协程(Quasar/Kotlin协程)8. Java并发工具进阶8.1 CountDownLatch应用// 初始化计数器 CountDownLatch latch new CountDownLatch(3); // 多个线程完成任务后计数 new Thread(() - { doTask1(); latch.countDown(); }).start(); // ...类似启动其他线程 // 主线程等待所有任务完成 latch.await(); // 阻塞直到计数器为0 System.out.println(所有任务完成);使用场景并行任务同步服务启动依赖多阶段测试8.2 CyclicBarrier实现CyclicBarrier barrier new CyclicBarrier(3, () - { System.out.println(所有线程到达屏障); }); IntStream.range(0, 3).forEach(i - new Thread(() - { System.out.println(线程 i 准备); barrier.await(); // 等待其他线程 System.out.println(线程 i 继续); }).start());特点可重复使用(reset)支持屏障动作可处理中断异常8.3 CompletableFuture组合CompletableFutureString query1 CompletableFuture.supplyAsync(() - queryService1()); CompletableFutureString query2 CompletableFuture.supplyAsync(() - queryService2()); CompletableFutureVoid combined CompletableFuture.allOf(query1, query2); combined.thenRun(() - { try { String result1 query1.get(); String result2 query2.get(); processResults(result1, result2); } catch (Exception e) { handleError(e); } });高级特性thenCompose (扁平化嵌套Future)handle (统一处理结果/异常)exceptionally (异常恢复)9. 现代并发编程趋势9.1 响应式编程模型Flux.range(1, 10) .parallel() // 并行处理 .runOn(Schedulers.parallel()) .map(i - compute(i)) .sequential() .subscribe(result - process(result));优势背压支持声明式并发更好的资源利用率9.2 协程与虚拟线程Java19引入的虚拟线程Thread.startVirtualThread(() - { System.out.println(Running on virtual thread); });特点轻量级内存开销约1KB由JVM调度非OS线程适合高并发I/O操作9.3 无锁数据结构ConcurrentLinkedQueueString queue new ConcurrentLinkedQueue(); // 生产者 new Thread(() - { queue.offer(message); }).start(); // 消费者 new Thread(() - { String msg queue.poll(); if (msg ! null) { process(msg); } }).start();性能优势完全无阻塞高并发下吞吐量稳定避免死锁风险10. 性能调优实战10.1 线程数计算公式通用公式线程数 CPU核心数 × (1 平均等待时间 / 平均计算时间)示例4核CPU任务50%时间在等待线程数 4 × (1 0.5/0.5) 8注意事项考虑其他进程的资源占用留出系统线程余量通过压测验证最佳值10.2 锁优化技巧减小锁粒度// 粗粒度锁 synchronized(this) { // 访问所有字段 } // 细粒度锁 Object field1Lock new Object(); Object field2Lock new Object(); synchronized(field1Lock) { // 只访问field1 }锁分离技术// 读写锁分离 ReentrantReadWriteLock rwLock new ReentrantReadWriteLock(); void read() { rwLock.readLock().lock(); try { // 读操作 } finally { rwLock.readLock().unlock(); } } void write() { rwLock.writeLock().lock(); try { // 写操作 } finally { rwLock.writeLock().unlock(); } }10.3 避免伪共享// 使用填充防止伪共享 class ContendedData { sun.misc.Contended volatile long value1; sun.misc.Contended volatile long value2; }原理CPU缓存行通常64字节不相关变量可能位于同一缓存行多核修改会导致缓存失效填充使变量独占缓存行11. 调试与问题诊断11.1 线程转储分析获取线程转储jstack pid thread_dump.txt关键信息解读BLOCKED (on object monitor)等待锁的线程WAITING (on object monitor)调用wait()的线程TIMED_WAITING (sleeping)sleep中的线程11.2 JConsole监控使用步骤启动应用时添加JMX参数java -Dcom.sun.management.jmxremote.port9010 \ -Dcom.sun.management.jmxremote.authenticatefalse \ -Dcom.sun.management.jmxremote.sslfalse \ -jar app.jar运行jconsole连接指定端口查看线程选项卡11.3 异步日志记录ExecutorService executor Executors.newSingleThreadExecutor(); Logger logger Logger.getLogger(async); void logAsync(String message) { executor.submit(() - logger.info(message)); }优势不阻塞业务线程单线程顺序写入日志文件避免多线程日志交错12. 设计模式应用12.1 线程安全单例class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance null) { synchronized(Singleton.class) { if (instance null) { instance new Singleton(); } } } return instance; } }关键点volatile防止指令重排序双重检查降低锁竞争私有构造器防止反射攻击12.2 生产者-消费者模式BlockingQueueItem queue new LinkedBlockingQueue(); // 生产者 void produce() { while (true) { Item item createItem(); queue.put(item); // 队列满时阻塞 } } // 消费者 void consume() { while (true) { Item item queue.take(); // 队列空时阻塞 process(item); } }变体实现使用Semaphore控制流量多级流水线设计工作窃取(Work Stealing)模式12.3 Fork-Join框架class FibonacciTask extends RecursiveTaskLong { final long n; FibonacciTask(long n) { this.n n; } protected Long compute() { if (n 10) return computeDirectly(); FibonacciTask f1 new FibonacciTask(n - 1); f1.fork(); FibonacciTask f2 new FibonacciTask(n - 2); return f2.compute() f1.join(); } } ForkJoinPool pool new ForkJoinPool(); long result pool.invoke(new FibonacciTask(30));适用场景可分治的大任务递归算法计算密集型操作13. 最佳实践总结13.1 线程命名规范// 自定义线程工厂 ThreadFactory factory r - { Thread t new Thread(r); t.setName(service-worker- t.getId()); return t; }; ExecutorService executor Executors.newFixedThreadPool(5, factory);命名建议包含业务含义如order-processor增加唯一标识ID/序号区分线程池来源13.2 异常处理策略// 全局未捕获异常处理器 Thread.setDefaultUncaughtExceptionHandler((t, e) - { logger.error(Thread t.getName() failed, e); // 可选重启线程等恢复操作 }); // 线程池任务异常处理 executor.submit(() - { try { doTask(); } catch (Exception e) { logger.error(Task failed, e); throw e; } });处理原则不要静默吞掉异常记录完整上下文信息考虑失败重试机制13.3 资源清理保证// try-with-resources自动关闭 try (ExecutorService executor Executors.newFixedThreadPool(5)) { executor.submit(task); } // 自动调用shutdown() // 手动清理示例 Runtime.getRuntime().addShutdownHook(new Thread(() - { executor.shutdownNow(); connectionPool.close(); }));关键点确保线程池最终关闭释放数据库连接等资源处理未完成的任务14. 常见问题解答14.1 如何选择线程池大小考虑因素任务类型CPU/IO密集型系统资源CPU核心数、内存响应时间要求任务优先级经验公式CPU密集型核心数 1IO密集型核心数 × (1 平均等待时间/平均计算时间)混合型通过压测确定最佳值14.2 synchronized和ReentrantLock如何选择对比项synchronizedReentrantLock实现方式JVM内置JDK实现锁获取自动释放必须手动unlock()可中断不支持支持lockInterruptibly()公平锁非公平可配置公平性条件变量一个可创建多个性能Java6后优化相当高竞争下略优选择建议简单场景用synchronized需要高级功能时用ReentrantLock优先考虑代码可读性14.3 如何避免内存可见性问题解决方案使用volatile修饰共享变量所有访问都通过synchronized保护使用原子变量类AtomicInteger等尽量使用不可变对象使用线程安全容器ConcurrentHashMap等示例// 不安全实现 class UnsafeCounter { private int count; public void increment() { count; } } // 安全方案1volatile 原子操作 class VolatileCounter { private volatile int count; private static final AtomicIntegerFieldUpdaterVolatileCounter updater AtomicIntegerFieldUpdater.newUpdater(VolatileCounter.class, count); public void increment() { updater.incrementAndGet(this); } } // 安全方案2synchronized class SynchronizedCounter { private int count; public synchronized void increment() { count; } } // 安全方案3原子类 class AtomicCounter { private AtomicInteger count new AtomicInteger(); public void increment() { count.incrementAndGet(); } }15. 实战案例分析15.1 高并发计数器实现class CompactCounter { private static final sun.misc.Unsafe UNSAFE; private static final long VALUE_OFFSET; static { try { Field f sun.misc.Unsafe.class.getDeclaredField(theUnsafe); f.setAccessible(true); UNSAFE (sun.misc.Unsafe) f.get(null); VALUE_OFFSET UNSAFE.objectFieldOffset( CompactCounter.class.getDeclaredField(value)); } catch (Exception e) { throw new Error(e); } } private volatile int value; public void increment() { int oldValue; do { oldValue value; } while (!UNSAFE.compareAndSwapInt(this, VALUE_OFFSET, oldValue, oldValue 1)); } public int get() { return value; } }优化点直接使用Unsafe避免AtomicInteger的对象头开销适合极端高性能场景需要谨慎处理内存可见性15.2 高效缓存实现class ConcurrentCacheK, V { private final ConcurrentHashMapK, V map new ConcurrentHashMap(); private final ConcurrentHashMapK, FutureTaskV tasks new ConcurrentHashMap(); public V get(K key, CallableV loader) throws Exception { FutureTaskV task tasks.get(key); if (task ! null) { return task.get(); } task new FutureTask(loader); FutureTaskV existing tasks.putIfAbsent(key, task); if (existing null) { task.run(); } else { task existing; } try { return task.get(); } catch (ExecutionException e) { tasks.remove(key); throw (Exception) e.getCause(); } } }设计亮点防止重复计算线程安全的惰性加载自动清理失败任务15.3 异步任务链CompletableFuture.supplyAsync(() - queryDatabase()) .thenApplyAsync(data - transformData(data), transformExecutor) .thenAcceptBoth( CompletableFuture.supplyAsync(() - queryExternalService()), (local, external) - mergeResults(local, external) ) .exceptionally(ex - { logger.error(Processing failed, ex); return null; });模式优势异步流水线处理灵活的组合操作统一的错误处理资源隔离不同阶段使用不同线程池16. 性能对比测试16.1 锁性能对比测试代码interface Counter { void increment(); long get(); } // 测试方法 void benchmark(Counter counter, int threads, int iterations) { ExecutorService executor Executors.newFixedThreadPool(threads); long start System.nanoTime(); ListFuture? futures new ArrayList(); for (int i 0; i threads; i) { futures.add(executor.submit(() - { for (int j 0; j iterations; j) { counter.increment(); } })); } for (Future? f : futures) f.get(); long duration System.nanoTime() - start; System.out.printf(%s: %d threads, %d ops, time%.2fms%n, counter.getClass().getSimpleName(), threads, threads * iterations, duration / 1_000_000.0); }典型结果4核CPUSynchronizedCounter: 4 threads, 1000000 ops, time320.15ms AtomicCounter: 4 threads, 1000000 ops, time112.47ms UnsafeCounter: 4 threads, 1000000 ops, time98.23ms16.2 线程池实现对比测试场景处理10000个短任务// 1. 固定大小线程池 ExecutorService fixed Executors.newFixedThreadPool(4); // 2. 缓存线程池 ExecutorService cached Executors.newCachedThreadPool(); // 3. ForkJoinPool ExecutorService forkJoin ForkJoinPool.commonPool(); // 测试方法 void testPool(ExecutorService executor, String name) { long start System.nanoTime(); ListFuture? futures new ArrayList(); for (int i 0; i 10000; i) { futures.add(executor.submit(() - shortTask())); } for (Future? f : futures) f.get(); long duration System.nanoTime() - start; System.out.printf(%s: %.2fms%n, name, duration / 1_000_000.0); }典型结果FixedThreadPool: 1250.34ms CachedThreadPool: 980.45ms ForkJoinPool: 850.21ms17. Java内存模型深入17.1 happens-before规则程序顺序规则同一线程中的每个操作happens-before于该线程中任意的后续操作监视器锁规则解锁操作happens-before于后续对同一锁的加锁操作volatile变量规则volatile字段的写操作happens-before于后续对该字段的读操作线程启动规则