
1. JUC是什么为什么需要它我第一次接触JUC是在一个高并发订单系统的性能优化项目中。当时系统在促销活动时频繁出现线程阻塞和死锁传统的synchronized关键字已经无法满足需求。JUCJava Util Concurrent这个包就像是为高并发场景量身定制的工具箱它提供了比基础线程API更强大的并发控制能力。JUC的核心价值在于解决了多线程编程中的三大痛点更精细的锁控制比如ReentrantLock的可中断获取锁特性更高效的线程协作CountDownLatch等同步器线程安全的数据结构ConcurrentHashMap等注意很多初学者会混淆java.util.concurrent和java.lang.Thread的关系。Thread是线程操作的基石而JUC是在此基础上构建的高层建筑。2. JUC的核心组件拆解2.1 原子变量类Atomic在计数器场景中传统的int操作需要同步块保护。而AtomicInteger的incrementAndGet()方法通过CASCompare-And-Swap指令实现无锁自增AtomicInteger counter new AtomicInteger(0); // 线程安全的自增 int newValue counter.incrementAndGet();CAS的底层原理是读取当前值V计算新值V只有当内存值仍等于V时才更新为V否则重试整个操作2.2 锁机制LocksReentrantLock比synchronized更灵活的特性包括可中断的锁获取超时获取锁公平/非公平模式选择典型用法Lock lock new ReentrantLock(); try { lock.lockInterruptibly(); // 可被中断的加锁 // 临界区代码 } finally { lock.unlock(); }2.3 并发集合CollectionsConcurrentHashMap的并发实现经历了多次演进JDK7采用分段锁JDK8改为CASsynchronized优化关键设计当链表长度超过8时转为红黑树使用示例ConcurrentMapString, Integer map new ConcurrentHashMap(); map.compute(key, (k, v) - v null ? 1 : v 1);2.4 线程池ExecutorThreadPoolExecutor的7个核心参数corePoolSize - 核心线程数maximumPoolSize - 最大线程数keepAliveTime - 空闲线程存活时间unit - 时间单位workQueue - 任务队列threadFactory - 线程工厂handler - 拒绝策略配置建议ExecutorService executor new ThreadPoolExecutor( 4, // 核心线程数 8, // 最大线程数 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy() );3. JUC实战中的经典问题3.1 死锁检测与预防使用jstack检测死锁时典型的死锁日志特征Found one Java-level deadlock: Thread-1: waiting to lock monitor 0x00007f88b4003e18 (object 0x000000076ab270c0) which is held by Thread-0 Thread-0: waiting to lock monitor 0x00007f88b4003d58 (object 0x000000076ab270d0) which is held by Thread-1预防死锁的JUC方案使用tryLock()设置超时按固定顺序获取多把锁使用LockSupport替代wait/notify3.2 线程池配置陷阱常见错误配置核心线程数过大导致上下文切换频繁使用无界队列导致OOM错误的拒绝策略导致任务丢失推荐监控指标ThreadPoolExecutor executor (ThreadPoolExecutor) Executors.newFixedThreadPool(4); // 获取活跃线程数 int activeCount executor.getActiveCount(); // 获取任务队列大小 int queueSize executor.getQueue().size();4. JUC性能优化实战4.1 锁优化技巧减少锁竞争的方法缩小临界区范围使用读写锁ReentrantReadWriteLock尝试锁升级StampedLockStampedLock示例StampedLock lock new StampedLock(); // 乐观读 long stamp lock.tryOptimisticRead(); // 验证期间是否有写操作 if (!lock.validate(stamp)) { stamp lock.readLock(); // 升级为悲观读 try { // 读取数据 } finally { lock.unlockRead(stamp); } }4.2 并发数据结构选择不同场景下的选择策略场景推荐实现特性高频读CopyOnWriteArrayList写时复制高频写ConcurrentLinkedQueue无锁队列键值存储ConcurrentHashMap分段锁延迟任务DelayQueue时间排序5. JUC在分布式系统中的应用5.1 限流实现基于Semaphore的简单限流Semaphore limiter new Semaphore(100); // 每秒100个请求 boolean acquired limiter.tryAcquire(50, TimeUnit.MILLISECONDS); if (acquired) { try { // 处理请求 } finally { limiter.release(); } }5.2 分布式锁模式虽然JUC本身是单机工具但其思想可用于设计分布式锁获取锁时设置超时对应tryLock使用看门狗机制续期对应锁重入释放锁时校验持有者对应锁归属Redisson的实现就借鉴了JUC的Lock接口设计。6. JUC源码学习路线建议的阅读顺序AtomicInteger → 理解CASAbstractQueuedSynchronizer → 理解锁框架ConcurrentHashMap → 理解并发数据结构ThreadPoolExecutor → 理解资源管理关键设计模式AQS使用的模板方法模式FutureTask的状态机设计ForkJoinPool的工作窃取算法我在阅读AQS源码时发现个有趣细节CLH队列的节点会自旋检查前驱节点状态而不是持续占用CPU// AbstractQueuedSynchronizer源码片段 for (;;) { Node pred node.prev; if (pred head tryAcquire(arg)) { setHead(node); pred.next null; return; } if (shouldParkAfterFailedAcquire(pred, node)) parkAndCheckInterrupt(); // 这里会挂起线程 }7. 常见面试问题深度解析7.1 ConcurrentHashMap扩容机制JDK8的扩容优化多线程协同扩容扩容期间仍然可以查询通过ForwardingNode标记迁移状态扩容触发条件// ConcurrentHashMap源码中的判断逻辑 if (check 0) { NodeK,V[] tab, nt; int n, sc; while (s (long)(sc sizeCtl) (tab table) ! null (n tab.length) MAXIMUM_CAPACITY) { // 触发扩容 } }7.2 ThreadLocal内存泄漏虽然不属于JUC但常被拿来比较ThreadLocalMap使用弱引用解决Key泄漏但Value仍可能泄漏必须配合remove()使用8. JUC的现代替代方案8.1 Project Loom的虚拟线程与传统线程池对比特性平台线程虚拟线程内存占用1MB几百KB创建成本高低调度方式OS调度JVM调度8.2 Reactive编程与JUC的异同都解决并发问题Reactor基于事件驱动更适合IO密集型场景示例对比// JUC方式 CompletableFuture.supplyAsync(() - fetchData()) .thenApply(data - process(data)) .thenAccept(result - save(result)); // Reactor方式 Mono.fromCallable(() - fetchData()) .map(data - process(data)) .doOnNext(result - save(result)) .subscribe();9. 监控与调试技巧9.1 JUC相关JVM参数关键参数-XX:PrintConcurrentLocks打印锁信息-Djava.util.concurrent.ForkJoinPool.common.parallelism8设置公共并行度-XX:UseSpinning开启自旋优化9.2 诊断工具推荐工具链jstack → 查看线程状态jconsole → 监控线程池Arthas → 动态诊断JProfiler → 锁竞争分析我在生产环境常用的Arthas命令watch java.util.concurrent.locks.ReentrantLock lock \ {params, target, returnObj} -x 310. 设计模式在JUC中的应用10.1 生产者-消费者模式BlockingQueue的四种实现对比实现类特性适用场景ArrayBlockingQueue有界数组固定容量场景LinkedBlockingQueue可选有界链表默认无界PriorityBlockingQueue优先级排序任务调度SynchronousQueue直接传递高吞吐场景10.2 Fork-Join模式递归任务示例class FibonacciTask extends RecursiveTaskInteger { final int n; FibonacciTask(int n) { this.n n; } protected Integer compute() { if (n 1) return n; FibonacciTask f1 new FibonacciTask(n - 1); f1.fork(); FibonacciTask f2 new FibonacciTask(n - 2); return f2.compute() f1.join(); } }实际项目中我常用ForkJoinPool处理树形结构的并行计算比如大型文档的并行处理图像分块处理递归目录扫描11. JUC版本演进关键变化11.1 JDK5到JDK8的变化重要新增CompletableFutureJDK8StampedLockJDK8ConcurrentHashMap优化JDK811.2 JDK9到JDK17的变化现代特性Reactive StreamsJDK9VarHandleJDK9虚拟线程预览JDK1912. 最佳实践与避坑指南12.1 锁使用原则我总结的三要三不要要明确锁的范围要控制锁的粒度要考虑可中断性不要在锁内调用外部方法不要嵌套使用不同锁不要忽略锁的释放12.2 线程池配置经验根据业务类型推荐配置业务类型核心线程数队列类型拒绝策略CPU密集型CPU核数1有界队列AbortPolicyIO密集型CPU核数*2无界队列CallerRunsPolicy混合型动态调整SynchronousQueueDiscardOldestPolicy13. 性能测试对比数据13.1 锁性能对比测试环境4核CPU100万次操作锁类型耗时(ms)synchronized450ReentrantLock320StampedLock(读)210StampedLock(写)38013.2 并发集合吞吐量测试场景10线程并发操作集合类型ops/sHashMap崩溃Collections.synchronizedMap120,000ConcurrentHashMap850,00014. 与其他语言并发库对比14.1 与Go的channel对比相似点都提供线程安全的数据交换都支持阻塞操作不同点channel更侧重通信JUC更侧重共享内存14.2 与C的std::async对比特性对比JUC的Future更丰富C的async更接近底层异常处理方式不同15. 经典书籍与学习资源推荐学习路径《Java并发编程实战》- 理论基础《Java并发编程之美》- 实践案例JDK源码 - 终极教材我个人特别推荐Doug Lea的论文《The java.util.concurrent Synchronizer Framework》这是理解AQS的最佳材料。