《Java 100 天进阶之路》并发编程与JUC详解(第51~60篇)核心知识点汇总
并发编程与JUC详解第51~60篇核心知识点汇总本阶段共10篇文章覆盖Java并发编程从基础到精通的完整链路是面试权重最高、区分度最大的模块之一。第51篇线程生命周期与创建方式 查看完整文章6种线程状态Thread.StateNEW线程创建但未启动new Thread()RUNNABLE可运行状态就绪 运行中JVM将两者合并BLOCKED阻塞状态等待获取监视器锁synchronized锁被占用WAITING无限期等待需显式唤醒wait()、join()、park()TIMED_WAITING有限期等待超时自动唤醒sleep(ms)、wait(ms)、join(ms)TERMINATED终止状态run()结束或异常退出4种线程创建方式继承Thread类不推荐单继承限制实现Runnable接口最常用Lambda写法实现Callable接口有返回值可抛异常线程池ExecutorService核心对比sleep() vs wait()sleep不释放锁wait释放锁sleep时间到自醒wait需notify唤醒start() vs run()start启动新线程run是普通方法调用虚拟线程JDK 21轻量级线程几百字节M:N调度适合高并发I/O密集型不适合CPU密集型第52篇synchronized深度解析 查看完整文章三种使用方式修饰实例方法 → 锁当前实例this修饰静态方法 → 锁当前类的Class对象修饰代码块 → 锁括号内指定对象推荐粒度最细锁升级全流程JDK 1.6无锁→偏向锁→轻量级锁→重量级锁单向升级不可逆偏向锁单线程场景Mark Word存线程ID无CAS开销轻量级锁轻度竞争自旋等待CASLock Record在栈帧重量级锁重度竞争OS互斥量ObjectMonitor_owner、_count、_EntryList、_WaitSetMark Word64位JVM存储锁状态、hashCode、分代年龄、偏向线程ID锁标志位01无锁/偏向、00轻量级、10重量级、11GC标记JVM优化自适应自旋锁JVM动态调整自旋次数锁消除逃逸分析移除无竞争锁锁粗化合并连续加锁/解锁关键陷阱JDK 15默认禁用偏向锁-XX:UseBiasedLocking可重新启用虚拟线程中慎用synchronized → 导致Pinning固定在载体线程第53篇volatile与JMM 查看完整文章JMMJava内存模型核心抽象结构主内存共享变量 工作内存CPU缓存JMM ≠ JVM内存结构——JMM管“怎么看见”JVM内存结构管“存哪里”三大特性原子性synchronized/锁、可见性volatile、有序性内存屏障volatile特性✅ 保证可见性写即刷主存读即强制重载✅ 禁止指令重排序内存屏障❌ 不保证原子性i是读-改-写三步内存屏障四种类型StoreStore禁止普通写重排到volatile写之前StoreLoad禁止volatile写重排到后续读写之后开销最大LoadLoad禁止volatile读后续普通读重排到前面LoadStore禁止volatile读后续普通写重排到前面Happens-Before规则volatile写 → volatile读核心规则程序顺序规则、锁规则、传递性DCL单例必须加volatile防止new Singleton()三步分配内存→初始化→引用赋值重排导致半初始化对象暴露 → NPE第54篇AQS抽象队列同步器 查看完整文章AQS核心三要素volatile int state同步状态0空闲0占用/重入/许可数CLH双向FIFO队列存储等待线程Node节点含thread、waitStatus、prev、next模板方法模式子类实现tryAcquire/tryRelease等AQS提供acquire/release骨架两种同步模式独占模式Exclusive同一时刻只有一个线程能获取 → ReentrantLock共享模式Shared同一时刻多个线程可获取 → Semaphore、CountDownLatchNode.waitStatusCANCELLED(1)、SIGNAL(-1)、CONDITION(-2)、PROPAGATE(-3)、0(初始)ReentrantLock可重入实现state计数当前线程是持有者时state解锁时state--归零释放第55篇线程池ThreadPoolExecutor 查看完整文章七大核心参数参数说明corePoolSize核心线程数常驻员工maximumPoolSize最大线程数核心非核心keepAliveTime非核心线程空闲存活时间unit时间单位workQueue工作队列BlockingQueuethreadFactory线程工厂自定义线程名handler拒绝策略四步执行流程当前线程数 corePoolSize → 创建核心线程执行核心线程满 → 任务放入队列等待队列满 → 当前线程数 maximumPoolSize → 创建非核心线程线程也满 → 执行拒绝策略四种拒绝策略AbortPolicy默认抛RejectedExecutionExceptionCallerRunsPolicy调用者线程执行可防止任务丢失会阻塞调用者DiscardPolicy静默丢弃新任务DiscardOldestPolicy丢弃队列最旧任务重新提交Executors陷阱禁止使用newFixedThreadPool无界LinkedBlockingQueue → 任务堆积 → OOMnewCachedThreadPoolmaxPoolSizeInteger.MAX_VALUE → 无限线程 → 资源耗尽线程数计算公式CPU密集型 CPU核数 1IO密集型 CPU核数 × 2第56篇死锁与排查工具 查看完整文章死锁四大必要条件Coffman条件互斥资源一次只能被一个线程占用持有并等待持有资源的同时等待其他资源不可剥夺资源只能主动释放不能强行剥夺循环等待线程之间形成等待环路排查工具jstack -l PID命令行首选输出Found one Java-level deadlock定位waiting to lock和locked行号jconsole图形化一键检测死锁VisualVM深度分析线程状态监控死锁 vs 活锁 vs 饥饿死锁永久阻塞不主动干预永不恢复活锁不阻塞但不断重试失败空转无推进饥饿有进展但极其缓慢低优先级线程预防策略破坏四大条件之一统一锁顺序破坏循环等待ReentrantLock.tryLock(timeout)超时破坏不可剥夺一次性申请所有资源失败则全部释放破坏持有并等待减少锁粒度使用ConcurrentHashMap等第57篇CompletableFuture异步编程 查看完整文章Future四大痛点阻塞获取结果get()异步变同步无法链式调用无法组合多个任务异常处理困难核心API方法说明supplyAsync(Supplier)有返回值的异步任务runAsync(Runnable)无返回值的异步任务thenApply(Function)同步转换结果同一线程thenApplyAsync(Function)异步转换结果新线程thenCompose(Function)串联异步任务扁平化thenCombine并行合并两个任务结果allOf等待所有任务完成VoidanyOf等待任意一个任务完成异常处理三件套exceptionally(Function)仅异常时触发返回兜底值handle(BiFunction)成功/失败都触发可继续链式处理whenComplete(BiConsumer)收尾工作不改变结果异常继续传播线程池配置禁止使用ForkJoinPool.commonPool()业务异步必须自建线程池CPU密集型接近CPU核心数IO密集型CPU核心数×2第58篇原子类与CAS 查看完整文章CAS三要素内存位置 V、预期值 A、新值 BCPU原子指令x86lock cmpxchg硬件保证原子性CAS失败 → 自旋重试for(;;)循环原子类五大分类基本类型AtomicInteger、AtomicLong、AtomicBoolean数组类型AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray引用类型AtomicReference、AtomicStampedReference解决ABA、AtomicMarkableReference属性更新器AtomicIntegerFieldUpdater等零内存开销字段必须volatile高性能累加器LongAdder、DoubleAdder、LongAccumulatorABA问题值 A→B→ACAS误判为未被修改 →AtomicStampedReference版本号解决LongAdder设计低并发直接CAS更新base高并发分段累加Cell[]各自累加最后求和Contended防止伪共享每个Cell独占缓存行性能是AtomicLong的4倍以上VarHandle替代UnsafeJDK 23重要变更Unsafe内存访问方法已废弃JEP 471推荐方案MethodHandles.lookup().findVarHandle()优势直接映射JVM字节码类型校验精细内存顺序控制第59篇ThreadLocal原理与内存泄漏 查看完整文章核心设计空间换时间每个线程独立变量副本实现线程间数据隔离JDK 1.8架构控制权反转ThreadLocal 不再维护全局Map每个Thread对象持有自己的ThreadLocalMapThreadLocal实例作为Map的keyEntry结构关键设计keyThreadLocal实例WeakReference弱引用value变量副本强引用内存泄漏完整链路ThreadLocal外部引用被置空 → GC回收ThreadLocal对象 → Entry.key变为null弱引用特性→ Entry.value仍是强引用无法回收 → 线程存活 → ThreadLocalMap存活 → null-key Entry永久残留 → 内存泄漏关键结论弱引用只解决了ThreadLocal对象的回收缓解泄漏不能解决value的回收根治方案try-finally保证remove()执行跨线程传递方案InheritableThreadLocal父子线程传递仅新建子线程时复制TransmittableThreadLocal阿里开源线程池场景上下文传递remove() vs set(null)remove()删除整个Entrykeyvalue彻底释放内存set(null)只设value为nullEntry仍存在内存泄漏未解决第60篇并发编程面试压轴题 查看完整文章本阶段共10篇内容对应第51~59篇的全部考点覆盖8大模块、30高频题。核心模块速览模块核心考点面试权重基础概念线程6种状态、sleep/wait、4种创建方式⭐⭐⭐⭐锁机制synchronized锁升级、Mark Word、ReentrantLock⭐⭐⭐⭐⭐JMM与volatile可见性、有序性、内存屏障、happens-before⭐⭐⭐⭐⭐AQS与并发工具核心三要素、独占/共享模式、Semaphore⭐⭐⭐⭐⭐线程池七大参数、执行流程、拒绝策略、Executors陷阱⭐⭐⭐⭐⭐死锁排查四大必要条件、jstack实战⭐⭐⭐⭐异步与无锁CompletableFuture编排、CAS三要素、ABA⭐⭐⭐⭐ThreadLocal内存泄漏根因、弱引用/强引用、remove⭐⭐⭐⭐